2016-03-27 11:49:47 +02:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Copyright ( C ) 2015 the OpenMoHAA team
This file is part of OpenMoHAA source code .
OpenMoHAA source code is free software ; you can redistribute it
and / or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation ; either version 2 of the License ,
or ( at your option ) any later version .
OpenMoHAA source code is distributed in the hope that it will be
useful , but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with OpenMoHAA source code ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
// navigate.cpp: C++ implementation of the A* search algorithm.
//
# include "g_local.h"
# include "navigate.h"
# include "misc.h"
# include "doors.h"
# include "actor.h"
# include "player.h"
2023-04-29 21:56:38 +02:00
# include "debuglines.h"
# include "scriptexception.h"
2016-03-27 11:49:47 +02:00
# define PATHFILE_VERSION 103
int path_checkthisframe ;
cvar_t * ai_showroutes ;
cvar_t * ai_showroutes_distance ;
cvar_t * ai_shownodenums ;
cvar_t * ai_shownode ;
cvar_t * ai_showallnode ;
cvar_t * ai_showpath ;
cvar_t * ai_fallheight ;
cvar_t * ai_debugpath ;
cvar_t * ai_pathchecktime ;
cvar_t * ai_pathcheckdist ;
static float * path_start ;
static float * path_end ;
static PathNode * Node ;
static float path_totaldir [ 2 ] ;
static float path_p [ 3 ] ;
static float path_startdir [ 2 ] ;
static Entity * IgnoreObjects [ MAX_GENTITIES ] ;
static int NumIgnoreObjects ;
static qboolean pathnodesinitialized = false ;
static qboolean loadingarchive = false ;
static qboolean pathnodescalculated = false ;
int ai_maxnode ;
MapCell PathSearch : : PathMap [ PATHMAP_GRIDSIZE ] [ PATHMAP_GRIDSIZE ] ;
PathNode * PathSearch : : open ;
int PathSearch : : findFrame ;
qboolean PathSearch : : m_bNodesloaded ;
qboolean PathSearch : : m_NodeCheckFailed ;
int PathSearch : : m_LoadIndex ;
PathNode * PathSearch : : pathnodes [ MAX_PATHNODES ] ;
int PathSearch : : nodecount ;
float PathSearch : : total_dist ;
2023-02-01 00:28:40 +01:00
const char * PathSearch : : last_error ;
2016-03-27 11:49:47 +02:00
byte * bulkNavMemory = NULL ;
byte * startBulkNavMemory = NULL ;
2018-08-19 08:26:59 +02:00
Vector PLAYER_BASE_MIN ( - 15.5f , - 15.5f , 0 ) ;
Vector PLAYER_BASE_MAX ( 15.5f , 15.5f , 0 ) ;
2016-03-27 11:49:47 +02:00
Vector testpos [ 200 ] ;
Vector ai_startpath ;
Vector ai_endpath ;
float NODE_MINS [ 3 ] = { - 15 , - 15 , 0 } ;
float NODE_MAXS [ 3 ] = { 15 , 15 , 94 } ;
float COLOR_PATHNODE_ERROR [ 3 ] = { 0 , 0 , 0 } ;
float COLOR_PATHNODE_COVER [ 3 ] = { 0 , 1 , 0 } ;
float COLOR_PATHNODE_CORNER_LEFT [ 3 ] = { 1 , 1 , 0 } ;
float COLOR_PATHNODE_CORNER_RIGHT [ 3 ] = { 0.7f , 1 , 0 } ;
float COLOR_PATHNODE_SNIPER [ 3 ] = { 1 , 0 , 0 } ;
float COLOR_PATHNODE_CRATE [ 3 ] = { 3 , 0 , 0 } ;
float COLOR_PATHNODE_CONCEALMENT [ 3 ] = { 0 , 0 , 1 } ;
float COLOR_PATHNODE_DUCK [ 3 ] = { 0 , 1 , 1 } ;
float COLOR_PATHNODE_DEFAULT [ 3 ] = { 1 , 0 , 1 } ;
int testcount = 0 ;
static ActorPath * test_path = NULL ;
struct {
float fMinRangeSquared ;
float fMaxRangeSquared ;
float fMinAngle ;
float fMaxAngle ;
}
g_AttackParms [ ] =
{
{ 64 * 64 , 2048 * 2048 , 150.0f , 210.0f } ,
{ 64 * 64 , 2048 * 2048 , 150.0f , 210.0f } ,
{ 96 * 96 , 2048 * 2048 , 320.0f , 40.0f } ,
} ;
PathSearch PathManager ;
int path_checksthisframe ;
void AI_AddNode
(
PathNode * node
)
{
int i = PathSearch : : nodecount ;
assert ( node ) ;
if ( i < MAX_PATHNODES )
{
if ( i > ai_maxnode )
{
ai_maxnode = i ;
}
PathSearch : : pathnodes [ i ] = node ;
node - > nodenum = i ;
PathSearch : : nodecount + + ;
return ;
}
gi . Error ( ERR_DROP , " Exceeded MAX_PATHNODES! \n " ) ;
}
qboolean CheckMove
(
Vector & origin ,
Vector & pos ,
short int * path_fallheight ,
float size
)
{
mmove_t mm ;
int i ;
float air_z ;
float fallheight ;
float test_fallheight ;
float error ;
trace_t trace ;
vec3_t dir ;
vec3_t end ;
memset ( & mm , 0 , sizeof ( mmove_t ) ) ;
VectorClear ( mm . velocity ) ;
VectorCopy ( origin , mm . origin ) ;
mm . desired_speed = 150.0f ;
mm . entityNum = ENTITYNUM_NONE ;
mm . tracemask = MASK_PATHSOLID ;
mm . frametime = 0.1f ;
mm . desired_dir [ 0 ] = pos [ 0 ] - origin [ 0 ] ;
mm . desired_dir [ 1 ] = pos [ 1 ] - origin [ 1 ] ;
VectorNormalize2D ( mm . desired_dir ) ;
mm . groundPlane = qfalse ;
mm . walking = qfalse ;
mm . mins [ 0 ] = - size ;
mm . mins [ 1 ] = - size ;
mm . mins [ 2 ] = 0 ;
mm . maxs [ 0 ] = size ;
mm . maxs [ 1 ] = size ;
mm . maxs [ 2 ] = 94.0f ;
testcount = 0 ;
fallheight = 0.0f ;
air_z = mm . origin [ 2 ] ;
for ( i = 200 ; i ! = 1 ; i - - )
{
testpos [ i - 1 ] = mm . origin ;
testcount + + ;
MmoveSingle ( & mm ) ;
if ( mm . groundPlane )
{
test_fallheight = air_z - mm . origin [ 2 ] ;
if ( test_fallheight > fallheight )
{
if ( test_fallheight > 1024.0f )
return false ;
fallheight = test_fallheight ;
}
air_z = mm . origin [ 2 ] ;
}
dir [ 0 ] = pos [ 0 ] - mm . origin [ 0 ] ;
dir [ 1 ] = pos [ 1 ] - mm . origin [ 1 ] ;
if ( DotProduct2D ( dir , mm . desired_dir ) < = 0.1f )
{
error = mm . origin [ 2 ] - pos [ 2 ] ;
gi . Printf ( " error = %f \n " , error ) ;
* path_fallheight = ( short ) fallheight ;
if ( fabs ( error ) > 94.0f )
{
if ( mm . groundPlane )
return false ;
mm . desired_dir [ 0 ] = dir [ 0 ] ;
mm . desired_dir [ 1 ] = dir [ 1 ] ;
VectorNormalize2D ( mm . desired_dir ) ;
}
else if ( error > 0.0f & & ! mm . groundPlane )
{
end [ 0 ] = mm . origin [ 0 ] ;
end [ 1 ] = mm . origin [ 1 ] ;
end [ 2 ] = pos [ 2 ] ;
trace = G_Trace ( mm . origin ,
mm . mins ,
mm . maxs ,
end ,
NULL ,
MASK_PATHSOLID ,
true ,
" CheckMove " ) ;
test_fallheight = mm . origin [ 2 ] - trace . endpos [ 2 ] ;
if ( test_fallheight < = 18.0f )
{
* path_fallheight = ( short ) test_fallheight + fallheight ;
return test_fallheight + fallheight < = 1024.0f ;
}
if ( mm . groundPlane )
return false ;
mm . desired_dir [ 0 ] = dir [ 0 ] ;
mm . desired_dir [ 1 ] = dir [ 1 ] ;
VectorNormalize2D ( mm . desired_dir ) ;
}
else
{
return true ;
}
}
if ( mm . hit_obstacle )
{
gi . DPrintf ( " obstacle hit \n " ) ;
return false ;
}
}
return false ;
}
/*****************************************************************************/
/*QUAKED info_pathnode (1 0 0) (-24 -24 0) (24 24 32) FLEE DUCK COVER DOOR JUMP LADDER
FLEE marks the node as a safe place to flee to . Actor will be removed when it reaches a flee node and is not visible to a player .
DUCK marks the node as a good place to duck behind during weapon fire .
COVER marks the node as a good place to hide behind during weapon fire .
DOOR marks the node as a door node . If an adjacent node has DOOR marked as well , the actor will only use the path if the door in between them is unlocked .
JUMP marks the node as one to jump from when going to the node specified by target .
" target " the pathnode to jump to .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Event EV_Path_SetNodeFlags
(
" spawnflags " ,
EV_DEFAULT ,
" i " ,
" node_flags " ,
" Sets the path nodes flags. " ,
EV_NORMAL
) ;
CLASS_DECLARATION ( SimpleEntity , PathNode , " info_pathnode " )
{
{ & EV_Path_SetNodeFlags , & PathNode : : SetNodeFlags } ,
{ & EV_IsTouching , & PathNode : : IsTouching } ,
{ & EV_Delete , & PathNode : : Remove } ,
{ & EV_Remove , & PathNode : : Remove } ,
{ NULL , NULL }
} ;
static Vector pathNodesChecksum ;
static int numLoadNodes = 0 ;
static int numNodes = 0 ;
void * PathNode : : operator new ( size_t size )
{
return PathManager . AllocPathNode ( ) ;
}
void PathNode : : operator delete ( void * ptr )
{
return PathManager . FreePathNode ( ptr ) ;
}
PathNode : : PathNode ( )
{
entflags | = EF_PATHNODE ;
findCount = 0 ;
numChildren = 0 ;
iAvailableTime = - 1 ;
if ( ! loadingarchive )
{
// our archive function will take care of this stuff
AI_AddNode ( this ) ;
nodeflags = 0 ;
virtualNumChildren = 0 ;
iAvailableTime = - 1 ;
Child = NULL ;
}
}
PathNode : : ~ PathNode ( )
{
entflags & = ~ EF_PATHNODE ;
}
void PathNode : : Claim
(
Entity * pClaimer
)
{
pLastClaimer = pClaimer ;
iAvailableTime = 0 ;
}
const_str PathNode : : GetSpecialAttack
(
Actor * pActor
)
{
int iSpecialAttack ;
const_str csAnimation ;
float fRangeSquared ;
float vDelta [ 2 ] ;
float fMinAngle ;
float fMaxAngle ;
if ( nodeflags & AI_CORNER_LEFT )
{
iSpecialAttack = 0 ;
csAnimation = STRING_ANIM_CORNERLEFT_SCR ;
}
else if ( nodeflags & AI_CORNER_RIGHT )
{
iSpecialAttack = 1 ;
csAnimation = STRING_ANIM_CORNERRIGHT_SCR ;
}
else
{
if ( nodeflags > = 0 )
2019-06-29 23:43:30 +02:00
return STRING_NULL ;
2016-03-27 11:49:47 +02:00
iSpecialAttack = 2 ;
csAnimation = STRING_ANIM_OVERATTACK_SCR ;
}
if ( pActor - > m_Enemy )
{
vDelta [ 0 ] = pActor - > m_Enemy - > origin [ 0 ] - origin [ 0 ] ;
vDelta [ 1 ] = pActor - > m_Enemy - > origin [ 1 ] - origin [ 1 ] ;
}
else
{
vDelta [ 0 ] = pActor - > m_vLastEnemyPos [ 0 ] - origin [ 0 ] ;
vDelta [ 1 ] = pActor - > m_vLastEnemyPos [ 1 ] - origin [ 1 ] ;
}
fRangeSquared = vDelta [ 0 ] * vDelta [ 0 ] + vDelta [ 1 ] * vDelta [ 1 ] ;
if ( fRangeSquared < g_AttackParms [ iSpecialAttack ] . fMinRangeSquared | | fRangeSquared > g_AttackParms [ iSpecialAttack ] . fMaxRangeSquared )
2019-06-29 23:43:30 +02:00
return STRING_NULL ;
2016-03-27 11:49:47 +02:00
fMinAngle = atan2 ( vDelta [ 0 ] , vDelta [ 1 ] ) * ( 180.0f / M_PI ) - angles [ 1 ] ;
if ( fMinAngle > - 360.0f )
{
if ( fMinAngle > = 0.0f )
{
if ( fMinAngle > = 720.0f )
fMaxAngle = fMinAngle - 720.0f ;
else if ( fMinAngle > = 360.0f )
fMaxAngle = fMinAngle - 360.0f ;
else
fMaxAngle = fMinAngle ;
}
else
{
fMaxAngle = fMinAngle + 360.0f ;
}
}
else
{
fMaxAngle = fMinAngle + 720.0f ;
}
if ( g_AttackParms [ iSpecialAttack ] . fMinAngle < = g_AttackParms [ iSpecialAttack ] . fMaxAngle )
{
if ( g_AttackParms [ iSpecialAttack ] . fMinAngle > fMaxAngle )
2019-06-29 23:43:30 +02:00
return STRING_NULL ;
2016-03-27 11:49:47 +02:00
}
else
{
if ( g_AttackParms [ iSpecialAttack ] . fMinAngle < = fMaxAngle )
2019-06-29 23:43:30 +02:00
return STRING_NULL ;
2016-03-27 11:49:47 +02:00
}
if ( fMaxAngle > g_AttackParms [ iSpecialAttack ] . fMaxAngle )
2019-06-29 23:43:30 +02:00
return STRING_NULL ;
2016-03-27 11:49:47 +02:00
return csAnimation ;
}
Entity * PathNode : : GetClaimHolder
(
void
) const
{
if ( iAvailableTime )
return NULL ;
else
return pLastClaimer ;
}
bool PathNode : : IsClaimedByOther
(
Entity * pPossibleClaimer
) const
{
if ( pLastClaimer = = pPossibleClaimer )
return false ;
if ( iAvailableTime )
{
return ( level . inttime < iAvailableTime ) ;
}
else
{
return ( pLastClaimer ! = NULL ) ;
}
}
qboolean PathNode : : IsTouching
(
Entity * e1
)
{
return e1 - > absmin [ 0 ] < = origin [ 0 ] + 15.5f & &
e1 - > absmin [ 1 ] < = origin [ 1 ] + 15.5f & &
e1 - > absmin [ 0 ] < = origin [ 2 ] + 94.0f & &
origin [ 0 ] - 15.5f < = e1 - > absmax [ 0 ] & &
origin [ 1 ] - 15.5f < = e1 - > absmax [ 1 ] & &
origin [ 2 ] + 0.0f < = e1 - > absmax [ 2 ] ;
}
void PathNode : : SetNodeFlags
(
Event * ev
)
{
nodeflags = ev - > GetInteger ( 1 ) ;
}
void PathNode : : IsTouching
(
Event * ev
)
{
Entity * ent = ev - > GetEntity ( 1 ) ;
if ( ! ent )
{
ScriptError ( " IsTouching used with a NULL entity. \n " ) ;
}
ev - > AddInteger ( IsTouching ( ev - > GetEntity ( 1 ) ) ) ;
}
void PathNode : : Remove
(
Event * ev
)
{
// Pathnodes mustn't be removed
ScriptError ( " Not allowed to delete a path node " ) ;
}
void PathNode : : setOriginEvent
(
Vector org
)
{
if ( ! PathManager . m_bNodesloaded )
{
origin = org ;
centroid = org ;
}
}
void PathNode : : Archive
(
Archiver & arc
)
{
}
void PathNode : : ArchiveDynamic
(
Archiver & arc
)
{
SimpleEntity : : SimpleArchive ( arc ) ;
arc . ArchiveObjectPosition ( this ) ;
arc . ArchiveSafePointer ( & pLastClaimer ) ;
arc . ArchiveInteger ( & iAvailableTime ) ;
arc . ArchiveInteger ( & numChildren ) ;
if ( numChildren ! = virtualNumChildren )
{
for ( int i = 0 ; i < virtualNumChildren ; i + + )
{
arc . ArchiveByte ( & Child [ i ] . numBlockers ) ;
arc . ArchiveShort ( & Child [ i ] . node ) ;
arc . ArchiveShort ( & Child [ i ] . fallheight ) ;
arc . ArchiveFloat ( & Child [ i ] . dist ) ;
arc . ArchiveVec2 ( Child [ i ] . dir ) ;
arc . ArchiveVec3 ( Child [ i ] . pos1 ) ;
arc . ArchiveVec3 ( Child [ i ] . pos2 ) ;
}
}
}
void PathNode : : ArchiveStatic
(
Archiver & arc
)
{
arc . ArchiveVector ( & origin ) ;
arc . ArchiveVector ( & centroid ) ;
arc . ArchiveInteger ( & nodeflags ) ;
arc . ArchiveInteger ( & virtualNumChildren ) ;
numChildren = virtualNumChildren ;
if ( arc . Loading ( ) )
{
bulkNavMemory - = virtualNumChildren * sizeof ( pathway_t ) * sizeof ( pathway_t * ) ;
Child = virtualNumChildren ? ( pathway_t * ) bulkNavMemory : NULL ;
}
for ( int i = 0 ; i < virtualNumChildren ; i + + )
{
arc . ArchiveShort ( & Child [ i ] . node ) ;
arc . ArchiveShort ( & Child [ i ] . fallheight ) ;
arc . ArchiveFloat ( & Child [ i ] . dist ) ;
arc . ArchiveVec2 ( Child [ i ] . dir ) ;
arc . ArchiveVec3 ( Child [ i ] . pos1 ) ;
arc . ArchiveVec3 ( Child [ i ] . pos2 ) ;
if ( arc . Loading ( ) )
Child [ i ] . numBlockers = 0 ;
}
}
void PathNode : : ConnectChild
(
int i
)
{
int j ;
pathway_t child = Child [ i ] ;
for ( j = i - 1 ; j > = numChildren ; j - - )
{
Child [ j + 1 ] = Child [ j ] ;
}
Child [ numChildren ] = child ;
numChildren + + ;
}
void PathNode : : DisconnectChild
(
int i
)
{
int j ;
pathway_t child = Child [ i ] ;
for ( j = i + 1 ; j < numChildren ; j + + )
{
Child [ j - 1 ] = Child [ j ] ;
}
numChildren - - ;
Child [ numChildren ] = child ;
}
void PathNode : : ConnectTo
(
PathNode * node
)
{
Child [ virtualNumChildren ] . node = nodenum ;
Child [ virtualNumChildren ] . numBlockers = 0 ;
virtualNumChildren + + ;
numChildren + + ;
}
bool PathNode : : CheckPathTo
(
PathNode * node
)
{
if ( virtualNumChildren < NUM_PATHSPERNODE )
{
CheckPathToDefault ( node , & Child [ virtualNumChildren ] ) ;
return true ;
}
else
{
Com_Printf ( " ^~^~^ %d paths per node at (%.2f %.2f %.2f) exceeded \n - use DONT_LINK on some nodes to conserve cpu and memory usage \n " , NUM_PATHSPERNODE , node - > origin [ 0 ] , node - > origin [ 1 ] , node - > origin [ 2 ] ) ;
PathSearch : : m_NodeCheckFailed = true ;
return false ;
}
}
void PathNode : : CheckPathToDefault
(
PathNode * node ,
pathway_t * pathway
)
{
float dist ;
float delta [ 2 ] ;
Vector start ;
Vector end ;
delta [ 0 ] = node - > origin [ 0 ] - origin [ 0 ] ;
delta [ 1 ] = node - > origin [ 1 ] - origin [ 1 ] ;
dist = VectorNormalize2D ( delta ) ;
if ( dist > = 384.0f )
return ;
start = origin + Vector ( 0 , 0 , 36.0f ) ;
end = start - Vector ( 0 , 0 , 2048.0f ) ;
trace_t trace = G_Trace (
start ,
PLAYER_BASE_MIN ,
PLAYER_BASE_MAX ,
end ,
NULL ,
MASK_PATHSOLID ,
qfalse ,
" droptofloor " ) ;
start = node - > origin + Vector ( 0 , 0 , 36.0f ) ;
end = start - Vector ( 0 , 0 , 2048.0f ) ;
trace_t trace2 = G_Trace (
start ,
PLAYER_BASE_MIN ,
PLAYER_BASE_MAX ,
end ,
NULL ,
MASK_PATHSOLID ,
qfalse ,
" droptofloor " ) ;
start = trace . endpos ;
end = trace2 . endpos ;
if ( CheckMove ( start , end , & pathway - > fallheight , 15.5f ) )
{
pathway - > dist = dist ;
pathway - > dir [ 0 ] = delta [ 0 ] ;
pathway - > dir [ 1 ] = delta [ 1 ] ;
VectorCopy ( start , pathway - > pos1 ) ;
VectorCopy ( end , pathway - > pos2 ) ;
Child [ virtualNumChildren ] . node = node - > nodenum ;
Child [ virtualNumChildren ] . numBlockers = 0 ;
virtualNumChildren + + ;
numChildren + + ;
}
}
void PathNode : : MarkTemporarilyBad
(
void
)
{
iAvailableTime = level . inttime + 5000 ;
pLastClaimer = NULL ;
}
void PathNode : : Relinquish
(
void
)
{
iAvailableTime = level . inttime + 4000 ;
}
void PathNode : : DrawConnections
(
void
)
{
int i ;
pathway_t * path ;
PathNode * node ;
for ( i = 0 ; i < numChildren ; i + + )
{
path = & Child [ i ] ;
node = PathSearch : : pathnodes [ path - > node ] ;
G_DebugLine ( origin + Vector ( " 0 0 24 " ) , node - > origin + Vector ( " 0 0 24 " ) , 0.7f , 0.7f , 0 , 1 ) ;
}
}
static bool IsValidPathnode
(
int spawnflags
)
{
if ( ( spawnflags & AI_DUCK ) & & ( spawnflags & AI_COVERFLAGS2 ) )
return false ;
if ( ( spawnflags & AI_CONCEALMENT ) & & ( spawnflags & AI_SNIPERFLAGS ) )
return false ;
if ( ( spawnflags & AI_CORNER_LEFT ) & & ( spawnflags & AI_COVER_LEFT_FLAGS ) )
return false ;
if ( ( spawnflags & AI_CORNER_RIGHT ) & & ( spawnflags & AI_COVER_RIGHT_FLAGS ) )
return false ;
if ( ( spawnflags & AI_SNIPER ) & & ( spawnflags & AI_CRATEFLAGS ) )
return false ;
if ( ( spawnflags & AI_ALL ) & & ( spawnflags & AI_COVERFLAGS3 ) )
return false ;
return true ;
}
static void GetPathnodeColor
(
int spawnflags ,
vec3_t color
)
{
if ( IsValidPathnode ( spawnflags ) )
{
if ( spawnflags & AI_CORNER_LEFT )
{
VectorCopy ( COLOR_PATHNODE_CORNER_LEFT , color ) ;
}
else if ( spawnflags & AI_CORNER_RIGHT )
{
VectorCopy ( COLOR_PATHNODE_CORNER_RIGHT , color ) ;
}
else if ( spawnflags & AI_DUCK )
{
VectorCopy ( COLOR_PATHNODE_DUCK , color ) ;
}
else if ( spawnflags & AI_SNIPER )
{
VectorCopy ( COLOR_PATHNODE_SNIPER , color ) ;
}
else if ( spawnflags & AI_CONCEALMENT )
{
VectorCopy ( COLOR_PATHNODE_CONCEALMENT , color ) ;
}
else if ( spawnflags & AI_COVER )
{
VectorCopy ( COLOR_PATHNODE_COVER , color ) ;
}
else if ( spawnflags & AI_CRATE )
{
VectorCopy ( COLOR_PATHNODE_CRATE , color ) ;
}
else
{
VectorCopy ( COLOR_PATHNODE_DEFAULT , color ) ;
}
}
else
{
VectorCopy ( COLOR_PATHNODE_ERROR , color ) ;
}
}
void DrawNode
(
int iNodeCount
)
{
Vector down ;
Vector up ;
Vector dir ;
Vector p1 ;
Vector p2 ;
Vector p3 ;
Vector p4 ;
Vector q1 ;
Vector q2 ;
Vector q3 ;
Vector q4 ;
Vector playerorigin ;
Vector aStart ;
Vector aEnd ;
PathNode * node ;
PathNode * nodelist [ 4096 ] ;
Vector end ;
Vector start ;
Vector p ;
vec3_t color ;
playerorigin = g_entities [ 0 ] . client - > ps . origin ;
if ( iNodeCount > 4096 )
iNodeCount = 4096 ;
if ( ai_showallnode - > integer )
iNodeCount = PathSearch : : DebugNearestNodeList2 ( playerorigin , nodelist , iNodeCount ) ;
else
iNodeCount = PathSearch : : DebugNearestNodeList ( playerorigin , nodelist , iNodeCount ) ;
if ( iNodeCount )
{
for ( int i = 0 ; i < iNodeCount ; i + + )
{
node = nodelist [ i ] ;
GetPathnodeColor ( node - > nodeflags , color ) ;
p1 . x = PLAYER_BASE_MAX . x + node - > origin . x ;
p1 . y = PLAYER_BASE_MAX . y + node - > origin . y ;
p2 . x = PLAYER_BASE_MAX . x + node - > origin . x ;
p2 . y = PLAYER_BASE_MIN . y + node - > origin . y ;
p3 . x = PLAYER_BASE_MIN . x + node - > origin . x ;
p3 . y = PLAYER_BASE_MIN . y + node - > origin . y ;
p4 . x = PLAYER_BASE_MIN . x + node - > origin . x ;
p4 . y = PLAYER_BASE_MAX . y + node - > origin . y ;
start = node - > origin + Vector ( 0 , 0 , 18 ) ;
end = node - > origin + Vector ( 0 , 0 , 18 ) ;
aStart = start ;
aEnd [ 0 ] = node - > origin [ 0 ] + cos ( M_PI / 180.0f * node - > angles [ 1 ] ) * 16.0f ;
aEnd [ 1 ] = node - > origin [ 1 ] + sin ( M_PI / 180.0f * node - > angles [ 1 ] ) * 16.0f ;
aEnd [ 2 ] = end [ 2 ] ;
G_DebugLine ( aStart , aEnd , 1 , 1 , 1 , 1 ) ;
p1 . z = node - > origin . z + 36.0f ;
p2 . z = node - > origin . z + 36.0f ;
p3 . z = node - > origin . z + 36.0f ;
p4 . z = node - > origin . z + 36.0f ;
G_DebugLine ( p1 , p2 , color [ 0 ] , color [ 1 ] , color [ 2 ] , 1 ) ;
G_DebugLine ( p2 , p3 , color [ 0 ] , color [ 1 ] , color [ 2 ] , 1 ) ;
G_DebugLine ( p3 , p4 , color [ 0 ] , color [ 1 ] , color [ 2 ] , 1 ) ;
G_DebugLine ( p4 , p1 , color [ 0 ] , color [ 1 ] , color [ 2 ] , 1 ) ;
q1 = p1 ;
q2 = p2 ;
q3 = p3 ;
q4 = p4 ;
q1 . z = node - > origin . z ;
q2 . z = node - > origin . z ;
q3 . z = node - > origin . z ;
q4 . z = node - > origin . z ;
G_DebugLine ( q1 , q2 , color [ 0 ] , color [ 1 ] , color [ 2 ] , 1 ) ;
G_DebugLine ( q2 , q3 , color [ 0 ] , color [ 1 ] , color [ 2 ] , 1 ) ;
G_DebugLine ( q3 , q4 , color [ 0 ] , color [ 1 ] , color [ 2 ] , 1 ) ;
G_DebugLine ( q4 , q1 , color [ 0 ] , color [ 1 ] , color [ 2 ] , 1 ) ;
G_DebugLine ( p1 , q1 , color [ 0 ] , color [ 1 ] , color [ 2 ] , 1 ) ;
G_DebugLine ( p2 , q2 , color [ 0 ] , color [ 1 ] , color [ 2 ] , 1 ) ;
G_DebugLine ( p3 , q3 , color [ 0 ] , color [ 1 ] , color [ 2 ] , 1 ) ;
G_DebugLine ( p4 , q4 , color [ 0 ] , color [ 1 ] , color [ 2 ] , 1 ) ;
}
}
else
{
G_DebugCircle ( playerorigin + Vector ( 0 , 0 , 48 ) , 128 , 1 , 0 , 0 , 1 , true ) ;
}
}
void DrawAllConnections
(
void
)
{
pathway_t * path ;
pathway_t * path2 ;
PathNode * node ;
PathNode * to ;
Vector down ;
Vector up ;
Vector dir ;
Vector p1 ;
Vector p2 ;
Vector p3 ;
Vector p4 ;
Vector playerorigin ;
qboolean showroutes ;
qboolean shownums ;
bool reverse ;
showroutes = ( ai_showroutes - > integer ! = 0 ) ;
shownums = ( ai_shownodenums - > integer ! = 0 ) ;
// Figure out where the camera is
if ( ! g_entities [ 0 ] . client )
return ;
playerorigin . x = g_entities [ 0 ] . client - > ps . origin [ 0 ] ;
playerorigin . y = g_entities [ 0 ] . client - > ps . origin [ 1 ] ;
playerorigin . z = g_entities [ 0 ] . client - > ps . origin [ 2 ] ;
playerorigin [ 2 ] + = g_entities [ 0 ] . client - > ps . viewheight ;
for ( int i = 0 ; i < PathSearch : : nodecount ; i + + )
{
node = PathSearch : : pathnodes [ i ] ;
if ( Vector ( node - > origin - playerorigin ) . length ( ) > ai_showroutes_distance - > integer )
{
continue ;
}
if ( shownums )
{
G_DrawDebugNumber ( node - > origin + Vector ( 0 , 0 , 14 ) , node - > nodenum , 1.5 , 1 , 1 , 0 ) ;
}
for ( int j = 0 ; j < node - > numChildren ; j + + )
{
path = & node - > Child [ j ] ;
if ( path - > fallheight > ai_fallheight - > integer )
continue ;
reverse = false ;
to = PathSearch : : pathnodes [ path - > node ] ;
for ( int k = to - > numChildren - 1 ; k > = 0 ; k - - )
{
path2 = & to - > Child [ k ] ;
if ( path2 - > fallheight < ai_fallheight - > integer & & PathSearch : : pathnodes [ path2 - > node ] = = node )
{
reverse = true ;
break ;
}
}
p1 = path - > pos1 + Vector ( 0 , 0 , 36 ) ;
p2 = path - > pos2 + Vector ( 0 , 0 , 36 ) ;
if ( node - > nodenum < to - > nodenum | | ! reverse )
{
// draw connected lines in green
G_DebugLine ( p1 , p2 , 0 , 1 , 0 , 1 ) ;
if ( ! reverse )
{
dir = Vector ( path - > pos2 ) - Vector ( path - > pos1 ) ;
dir . z = 0 ;
VectorNormalize ( dir ) ;
p3 = dir * 8.0f + dir * 8.0f ;
p4 = dir * 8.0f ;
p4 . z + = 8.0f ;
G_DebugLine ( p1 + p3 + up , p1 + p3 + up - p4 , 1 , 0 , 0 , 1 ) ;
p4 . z - = 16.0f ;
G_DebugLine ( p1 + p3 + down , p1 + p3 + down - p4 , 1 , 0 , 0 , 1 ) ;
}
}
}
if ( ! node - > numChildren )
{
// Put a little X where the node is to show that it had no connections
p1 = node - > origin ;
p1 . z + = 2 ;
if ( node - > nodeflags & PATH_DONT_LINK )
{
G_DebugCircle ( p1 , 12 , 0 , 0 , 1 , 1 , true ) ;
}
else
{
p2 = Vector ( 12 , 12 , 0 ) ;
G_DebugLine ( p1 - p2 , p1 + p2 , 1 , 0 , 0 , 1 ) ;
p2 . x = - 12 ;
G_DebugLine ( p1 - p2 , p1 + p2 , 1 , 0 , 0 , 1 ) ;
}
}
}
}
MapCell : : MapCell ( )
{
numnodes = 0 ;
nodes = NULL ;
}
MapCell : : ~ MapCell ( )
{
numnodes = 0 ;
nodes = NULL ;
}
qboolean MapCell : : AddNode
(
PathNode * node
)
{
nodes [ numnodes ] = ( short ) node - > nodenum ;
numnodes + + ;
return true ;
}
int MapCell : : NumNodes
(
void
)
{
return numnodes ;
}
/* All
work and no play
makes Jim a dull boy . All
work and no play makes Jim a
dull boy . All work and no play
makes Jim a dull boy . All work and no
play makes Jim a dull boy . All work and
no play makes Jim a dull boy . All work and
no play makes Jim a dull boy . All work and no
play makes Jim a dull boy . All work and no play
makes Jim a dull boy . All work and no play makes
Jim a dull boy . All work and no play makes Jim a
dull boy . All work and no play makes Jim a dull boy .
All work and no play makes Jim a dull boy . All work
and no play makes Jim a dull boy . All work and no play
makes Jim a dull boy . All work and no play makes Jim a
dull boy . All work and no play makes Jim a dull boy . All
work and no play makes Jim a dull boy . All work and no
play makes Jim a dull boy . All work and no play makes Jim
a dull boy . All work and no play makes Jim a dull boy .
All work and no play makes Jim a dull boy . All work and
no play makes Jim a dull boy . All work and no play makes
Jim a dull boy . All work and no play makes Jim a dull
boy . All work and no play makes Jim a dull boy . All work
and no play makes Jim a dull boy . All work and no play
makes Jim a dull boy . All work and no play makes Jim a
dull boy . All work and no play makes Jim a dull boy . All
work and no play makes Jim a dull boy . All work and no
play makes Jim a dull boy . All work and no play makes
Jim a dull boy . All work and no play makes Jim a dull
boy . All work and no play makes Jim a dull boy . All
work and no play makes Jim a dull boy . All work and
no play makes Jim a dull boy . All work and no
play makes Jim a dull boy . All work and no play
makes Jim a dull boy . All work and no play
makes Jim a dull boy . All work and no play
makes Jim a dull boy . All work and no
play makes Jim a dull boy . All work
and no play makes Jim a dull boy .
All work and no play makes
Jim a dull boy . All work
and no play makes
Jim a
*/
CLASS_DECLARATION ( Class , PathSearch , NULL )
{
{ NULL , NULL }
} ;
PathSearch : : PathSearch ( )
{
memset ( pathnodes , 0 , sizeof ( pathnodes ) ) ;
open = 0 ;
findFrame = 0 ;
}
PathSearch : : ~ PathSearch ( )
{
ResetNodes ( ) ;
}
void PathSearch : : AddToGrid
(
PathNode * node ,
int x ,
int y
)
{
MapCell * cell ;
if ( x > PATHMAP_GRIDSIZE | | y > PATHMAP_GRIDSIZE )
cell = NULL ;
else
cell = & PathMap [ x ] [ y ] ;
if ( ! cell )
return ;
if ( cell - > NumNodes ( ) > = PATHMAP_NODES )
Com_Printf ( " ^~^~^ PathSearch::AddToGrid: Node overflow at ( %d, %d ) \n " , x , y ) ;
else
cell - > AddNode ( node ) ;
}
int PathSearch : : NodeCoordinate
(
float coord
)
{
float c ;
//return ( ( int )coord + MAX_MAP_BOUNDS - ( PATHMAP_CELLSIZE / 2 ) ) / PATHMAP_CELLSIZE;
c = coord + MAX_MAP_BOUNDS - ( PATHMAP_CELLSIZE / 2 ) ;
if ( c < 0 )
c = coord + MAX_MAP_BOUNDS + ( PATHMAP_CELLSIZE / 2 ) - 1 ;
return ( int ) c > > 8 ;
}
int PathSearch : : GridCoordinate
(
float coord
)
{
float c ;
//return ( ( int )coord + MAX_MAP_BOUNDS ) / PATHMAP_CELLSIZE;
c = coord + MAX_MAP_BOUNDS ;
if ( c < 0 )
c = coord + MAX_MAP_BOUNDS + PATHMAP_CELLSIZE - 1 ;
return ( int ) c > > 8 ;
}
void PathSearch : : AddNode
(
PathNode * node
)
{
int x ;
int y ;
assert ( node ) ;
x = NodeCoordinate ( node - > origin [ 0 ] ) ;
y = NodeCoordinate ( node - > origin [ 1 ] ) ;
AddToGrid ( node , x , y ) ;
AddToGrid ( node , x + 1 , y ) ;
AddToGrid ( node , x , y + 1 ) ;
AddToGrid ( node , x + 1 , y + 1 ) ;
}
void PathSearch : : LoadAddToGrid
(
int x ,
int y
)
{
MapCell * cell ;
if ( x > PATHMAP_GRIDSIZE | | y > PATHMAP_GRIDSIZE )
cell = NULL ;
else
cell = & PathMap [ x ] [ y ] ;
if ( cell )
cell - > numnodes + + ;
}
void PathSearch : : LoadAddToGrid2
(
PathNode * node ,
int x ,
int y
)
{
MapCell * cell ;
if ( x > PATHMAP_GRIDSIZE | | y > PATHMAP_GRIDSIZE )
cell = NULL ;
else
cell = & PathMap [ x ] [ y ] ;
if ( cell )
cell - > AddNode ( node ) ;
}
MapCell * PathSearch : : GetNodesInCell
(
int x ,
int y
)
{
if ( ( x < 0 ) | | ( x > = PATHMAP_GRIDSIZE ) | | ( y < 0 ) | | ( y > = PATHMAP_GRIDSIZE ) )
{
return NULL ;
}
return & PathMap [ x ] [ y ] ;
}
MapCell * PathSearch : : GetNodesInCell
(
float * pos
)
{
int x ;
int y ;
x = GridCoordinate ( pos [ 0 ] ) ;
y = GridCoordinate ( pos [ 1 ] ) ;
return GetNodesInCell ( x , y ) ;
}
PathNode * PathSearch : : DebugNearestStartNode
(
float * pos ,
Entity * ent
)
{
PathNode * node = NULL ;
int i ;
MapCell * cell ;
int nodes [ 128 ] ;
vec3_t deltas [ 128 ] ;
vec3_t start ;
vec3_t end ;
cell = GetNodesInCell ( pos ) ;
if ( ! cell )
return NULL ;
int node_count = NearestNodeSetup ( pos , cell , nodes , deltas ) ;
if ( ! node_count )
return NULL ;
VectorCopy ( pos , start ) ;
start [ 2 ] + = 32.0f ;
for ( i = 0 ; i < node_count ; i + + )
{
node = pathnodes [ cell - > nodes [ nodes [ i ] ] ] ;
VectorCopy ( start , end ) ;
VectorAdd ( end , deltas [ nodes [ i ] ] , end ) ;
Vector vStart = start ;
Vector vMins = Vector ( - 15 , - 15 , 0 ) ;
Vector vMaxs = Vector ( 15 , 15 , 62 ) ;
Vector vEnd = end ;
if ( G_SightTrace (
vStart ,
vMins ,
vMaxs ,
vEnd ,
ent ,
NULL ,
MASK_TARGETPATH ,
qtrue ,
" PathSearch::DebugNearestStartNode " ) )
{
return node ;
}
}
return pathnodes [ cell - > nodes [ nodes [ 0 ] ] ] ;
}
PathNode * PathSearch : : NearestStartNode
(
float * pos ,
SimpleActor * ent
)
{
2018-09-17 23:50:38 +02:00
PathNode * node = NULL ;
int i ;
MapCell * cell ;
int nodes [ 128 ] ;
vec3_t deltas [ 128 ] ;
vec3_t start ;
vec3_t end ;
cell = GetNodesInCell ( pos ) ;
if ( ! cell )
return NULL ;
int node_count = NearestNodeSetup ( pos , cell , nodes , deltas ) ;
int n = 0 ;
int j = 0 ;
VectorCopy ( pos , start ) ;
start [ 2 ] + = 32.0f ;
Vector vMins = Vector ( - 15 , - 15 , 0 ) ;
Vector vMaxs = Vector ( 15 , 15 , 62 ) ;
for ( i = 0 ; i < node_count ; i + + )
{
node = pathnodes [ cell - > nodes [ nodes [ i ] ] ] ;
VectorAdd ( start , deltas [ nodes [ i ] ] , end ) ;
Vector vStart = start ;
Vector vEnd = end ;
if ( G_SightTrace (
vStart ,
vMins ,
vMaxs ,
vEnd ,
( gentity_t * ) NULL ,
( gentity_t * ) NULL ,
1107437825 , //FIXME: macro
qtrue ,
" PathSearch::NearestStartNode 1 " ) )
{
ent - > m_NearestNode = node ;
ent - > m_vNearestNodePos = end ;
return node ;
}
}
2023-02-07 20:49:31 +01:00
if ( ( ent - > m_NearestNode & &
2018-09-17 23:50:38 +02:00
( G_SightTrace (
Vector ( start ) ,
vMins ,
vMaxs ,
ent - > m_vNearestNodePos ,
2023-02-07 20:49:31 +01:00
( gentity_t * ) ent ,
( gentity_t * ) NULL ,
2018-09-17 23:50:38 +02:00
1073883393 , //FIXME: macro
qtrue ,
2023-02-07 20:49:31 +01:00
" PathSearch::NearestStartNode 2 " ) ) )
2018-09-17 23:50:38 +02:00
| | node_count < = 0
)
{
node = ent - > m_NearestNode ;
}
else
{
node = pathnodes [ cell - > nodes [ nodes [ 0 ] ] ] ;
}
return node ;
2016-03-27 11:49:47 +02:00
}
PathNode * PathSearch : : NearestEndNode
(
float * pos
)
{
PathNode * node = NULL ;
int i ;
MapCell * cell ;
int nodes [ 128 ] ;
vec3_t deltas [ 128 ] ;
vec3_t start ;
vec3_t end ;
cell = GetNodesInCell ( pos ) ;
if ( ! cell )
return NULL ;
int node_count = NearestNodeSetup ( pos , cell , nodes , deltas ) ;
int n = 0 ;
int j = 0 ;
if ( ! node_count )
return NULL ;
VectorCopy ( pos , start ) ;
start [ 2 ] + = 32.0f ;
for ( i = 0 ; i < node_count ; i + + )
{
node = pathnodes [ cell - > nodes [ nodes [ i ] ] ] ;
2018-09-17 23:50:38 +02:00
VectorAdd ( start , deltas [ nodes [ i ] ] , end ) ;
2016-03-27 11:49:47 +02:00
Vector vStart = start ;
Vector vMins = Vector ( - 15 , - 15 , 0 ) ;
Vector vMaxs = Vector ( 15 , 15 , 62 ) ;
Vector vEnd = end ;
if ( G_SightTrace (
vStart ,
vMins ,
vMaxs ,
vEnd ,
( gentity_t * ) NULL ,
( gentity_t * ) NULL ,
MASK_TARGETPATH ,
qtrue ,
" PathSearch::NearestEndNode " ) )
{
return node ;
}
}
return pathnodes [ cell - > nodes [ nodes [ 0 ] ] ] ;
}
int PathSearch : : DebugNearestNodeList
(
float * pos ,
PathNode * * nodelist ,
int iMaxNodes
)
{
PathNode * node ;
int i ;
MapCell * cell ;
int nodes [ 128 ] ;
vec3_t deltas [ 128 ] ;
vec3_t start ;
vec3_t end ;
cell = GetNodesInCell ( pos ) ;
if ( ! cell )
return 0 ;
int node_count = NearestNodeSetup ( pos , cell , nodes , deltas ) ;
int n = 0 ;
int j = 0 ;
for ( i = 0 ; i < node_count & & j < iMaxNodes ; i + + )
{
node = pathnodes [ cell - > nodes [ nodes [ i ] ] ] ;
VectorCopy ( pos , start ) ;
VectorCopy ( pos , end ) ;
VectorAdd ( end , deltas [ i ] , end ) ;
Vector vStart = start ;
Vector vMins = Vector ( - 15 , - 15 , 0 ) ;
Vector vMaxs = Vector ( 15 , 15 , 62 ) ;
Vector vEnd = end ;
if ( G_SightTrace (
vStart ,
vMins ,
vMaxs ,
vEnd ,
( gentity_t * ) NULL ,
( gentity_t * ) NULL ,
MASK_PATHSOLID ,
qtrue ,
" PathSearch::DebugNearestNodeList " ) )
{
nodelist [ n ] = node ;
n + + ;
}
}
if ( ! n & & node_count )
{
nodelist [ 0 ] = pathnodes [ cell - > nodes [ nodes [ 0 ] ] ] ;
return 1 ;
}
else
{
return n ;
}
return 0 ;
}
int PathSearch : : DebugNearestNodeList2
(
float * pos ,
PathNode * * nodelist ,
int iMaxNodes
)
{
vec3_t delta ;
PathNode * node ;
float dist ;
int n = 0 ;
int i ;
int j ;
static float node_dist [ MAX_PATHNODES ] ;
int node_count ;
node_count = nodecount ;
for ( i = 0 ; i < node_count ; i + + )
{
node = pathnodes [ i ] ;
if ( pos [ 2 ] > node - > origin [ 2 ] + 94.0f )
continue ;
if ( node - > origin [ 2 ] > pos [ 2 ] + 94.0f )
continue ;
delta [ 0 ] = node - > origin [ 0 ] - pos [ 0 ] ;
delta [ 1 ] = node - > origin [ 1 ] - pos [ 1 ] ;
delta [ 2 ] = node - > origin [ 2 ] - pos [ 2 ] ;
dist = VectorLengthSquared ( delta ) ;
for ( j = n ; j > 0 ; j - - )
{
if ( dist > = node_dist [ j - 1 ] )
break ;
node_dist [ j ] = node_dist [ j - 1 ] ;
nodelist [ j ] = nodelist [ j - 1 ] ;
}
n + + ;
nodelist [ j ] = node ;
node_dist [ j ] = dist ;
}
return n ;
}
void PathSearch : : ArchiveStaticLoad
(
Archiver & arc
)
{
int i ;
PathNode * node ;
int total_nodes ;
int total_children ;
int x ;
int y ;
int size ;
loadingarchive = true ;
arc . ArchiveInteger ( & nodecount ) ;
arc . ArchiveInteger ( & total_nodes ) ;
arc . ArchiveInteger ( & total_children ) ;
size = total_nodes + total_children * ( sizeof ( pathway_t ) * 2 ) + nodecount * ( sizeof ( PathNode ) / 2 ) ;
2023-01-30 16:26:38 +01:00
size * = sizeof ( void * ) / 2 ;
2016-03-27 11:49:47 +02:00
gi . DPrintf ( " %d memory allocated for navigation. \n " , size ) ;
if ( size )
startBulkNavMemory = ( byte * ) gi . Malloc ( size ) ;
else
startBulkNavMemory = NULL ;
bulkNavMemory = startBulkNavMemory + size ;
for ( i = 0 ; i < nodecount ; i + + )
{
node = new PathNode ;
arc . ArchiveObjectPosition ( node ) ;
node - > ArchiveStatic ( arc ) ;
node - > nodenum = i ;
pathnodes [ i ] = node ;
if ( ! ( node - > nodeflags & PATH_DONT_LINK ) )
{
x = NodeCoordinate ( node - > origin [ 0 ] ) ;
y = NodeCoordinate ( node - > origin [ 1 ] ) ;
LoadAddToGrid ( x , y ) ;
LoadAddToGrid ( x + 1 , y ) ;
LoadAddToGrid ( x , y + 1 ) ;
LoadAddToGrid ( x + 1 , y + 1 ) ;
}
}
for ( x = 0 ; x < PATHMAP_GRIDSIZE ; x + + )
{
for ( y = 0 ; y < PATHMAP_GRIDSIZE ; y + + )
{
bulkNavMemory - = PathMap [ x ] [ y ] . numnodes * sizeof ( short ) ;
PathMap [ x ] [ y ] . nodes = PathMap [ x ] [ y ] . numnodes ? ( short * ) bulkNavMemory : NULL ;
PathMap [ x ] [ y ] . numnodes = 0 ;
}
}
for ( i = 0 ; i < nodecount ; i + + )
{
node = pathnodes [ i ] ;
if ( ! ( node - > nodeflags & PATH_DONT_LINK ) )
{
x = NodeCoordinate ( node - > origin [ 0 ] ) ;
y = NodeCoordinate ( node - > origin [ 1 ] ) ;
LoadAddToGrid2 ( node , x , y ) ;
LoadAddToGrid2 ( node , x + 1 , y ) ;
LoadAddToGrid2 ( node , x , y + 1 ) ;
LoadAddToGrid2 ( node , x + 1 , y + 1 ) ;
}
}
loadingarchive = false ;
}
void PathSearch : : ArchiveStaticSave
(
Archiver & arc
)
{
int i ;
PathNode * node ;
int total_nodes = 0 ;
int total_children = 0 ;
int x = 0 ;
int y = 0 ;
for ( x = 0 ; x < PATHMAP_GRIDSIZE ; x + + )
{
for ( y = 0 ; y < PATHMAP_GRIDSIZE ; y + + )
{
total_nodes + = PathMap [ x ] [ y ] . NumNodes ( ) ;
}
}
for ( i = 0 ; i < nodecount ; i + + )
{
node = pathnodes [ i ] ;
total_children + = node - > virtualNumChildren ;
}
arc . ArchiveInteger ( & nodecount ) ;
arc . ArchiveInteger ( & total_nodes ) ;
arc . ArchiveInteger ( & total_children ) ;
for ( i = 0 ; i < nodecount ; i + + )
{
node = pathnodes [ i ] ;
arc . ArchiveObjectPosition ( node ) ;
node - > ArchiveStatic ( arc ) ;
}
}
void PathSearch : : ArchiveLoadNodes
(
void
)
{
Archiver arc ;
qboolean success ;
success = qfalse ;
if ( arc . Read ( level . m_pathfile , false ) )
{
int file_version ;
str maptime ;
// get file values
arc . ArchiveInteger ( & file_version ) ;
if ( file_version ! = PATHFILE_VERSION )
{
Com_Printf ( " Expecting version %d path file. Path file is version %d. \n " , PATHFILE_VERSION , file_version ) ;
arc . Close ( ) ;
return ;
}
arc . ArchiveString ( & maptime ) ;
if ( gi . MapTime ( ) = = maptime & & gi . FS_FileNewer ( level . m_mapfile . c_str ( ) , level . m_pathfile . c_str ( ) ) < = 0 )
{
arc . ArchiveInteger ( & m_NodeCheckFailed ) ;
if ( ! g_nodecheck - > integer | | ! m_NodeCheckFailed )
{
ArchiveStaticLoad ( arc ) ;
m_bNodesloaded = arc . NoErrors ( ) ;
}
else
{
gi . Printf ( " Rebuilding pathnodes to view node errors. \n " ) ;
}
}
else
{
gi . Printf ( " Pathnodes have changed, rebuilding. \n " ) ;
}
}
arc . Close ( ) ;
}
qboolean PathSearch : : ArchiveSaveNodes
(
void
)
{
Archiver arc ;
str maptime ;
int tempInt ;
arc . Create ( level . m_pathfile ) ;
tempInt = PATHFILE_VERSION ;
arc . ArchiveInteger ( & tempInt ) ;
maptime = gi . MapTime ( ) ;
arc . ArchiveString ( & maptime ) ;
arc . ArchiveInteger ( & m_NodeCheckFailed ) ;
ArchiveStaticSave ( arc ) ;
arc . Close ( ) ;
return true ;
}
void PathSearch : : Connect
(
PathNode * node
)
{
int x ;
int y ;
findFrame + + ;
node - > findCount = findFrame ;
x = NodeCoordinate ( node - > origin [ 0 ] ) ;
y = NodeCoordinate ( node - > origin [ 1 ] ) ;
if ( Connect ( node , x - 1 , y - 1 ) )
{
if ( Connect ( node , x - 1 , y ) )
{
if ( Connect ( node , x - 1 , y + 1 ) )
{
if ( Connect ( node , x , y - 1 ) )
{
if ( Connect ( node , x , y ) )
{
if ( Connect ( node , x , y + 1 ) )
{
if ( Connect ( node , x + 1 , y - 1 ) )
{
if ( Connect ( node , x + 1 , y ) )
{
Connect ( node , x + 1 , y + 1 ) ;
}
}
}
}
}
}
}
}
}
bool PathSearch : : Connect
(
PathNode * node ,
int x ,
int y
)
{
MapCell * cell ;
int i ;
PathNode * node2 ;
if ( x > PATHMAP_GRIDSIZE | | y > PATHMAP_GRIDSIZE )
cell = NULL ;
else
cell = & PathMap [ x ] [ y ] ;
if ( ! cell )
return true ;
if ( cell - > numnodes < = 0 )
return true ;
for ( i = 0 ; i < cell - > numnodes ; i + + )
{
node2 = pathnodes [ cell - > nodes [ i ] ] ;
if ( node2 - > findCount ! = findFrame )
{
node2 - > findCount = findFrame ;
if ( ! node - > CheckPathTo ( node2 ) )
return false ;
}
}
return true ;
}
void PathSearch : : ShowNodes
(
void
)
{
if ( g_entities - > client )
{
if ( ai_shownode - > integer )
{
DrawNode ( ai_shownode - > integer ) ;
}
if ( ai_showroutes - > integer | | ai_shownodenums - > integer )
{
DrawAllConnections ( ) ;
}
}
if ( ai_showpath - > integer )
{
if ( ! test_path )
test_path = new ActorPath ;
if ( ai_showpath - > integer = = 1 )
{
ai_startpath = g_entities [ 0 ] . entity - > origin ;
}
if ( ai_showpath - > integer = = 2 )
{
ai_endpath = g_entities [ 0 ] . entity - > origin ;
}
if ( ai_showpath - > integer < = 2 )
{
test_path - > SetFallHeight ( ai_fallheight - > integer ) ;
test_path - > FindPath ( ai_startpath , ai_endpath , NULL , 0 , NULL , 0 ) ;
}
if ( ai_showpath - > integer = = 3 )
{
if ( test_path - > CurrentNode ( ) )
{
test_path - > UpdatePos ( g_entities [ 0 ] . entity - > origin ) ;
Vector vStart = g_entities [ 0 ] . entity - > origin + Vector ( 0 , 0 , 32 ) ;
Vector vEnd = g_entities [ 0 ] . entity - > origin + test_path - > CurrentDelta ( ) + Vector ( 0 , 0 , 32 ) ;
G_DebugLine ( vStart , vEnd , 1 , 1 , 0 , 1 ) ;
}
}
G_DebugLine ( ai_startpath , ai_endpath , 0 , 0 , 1 , 1 ) ;
if ( test_path - > CurrentNode ( ) )
{
PathInfo * pos = test_path - > CurrentNode ( ) ;
while ( pos ! = test_path - > LastNode ( ) )
{
Vector vStart = pos - > point + Vector ( 0 , 0 , 32 ) ;
pos - - ;
Vector vEnd = pos - > point + Vector ( 0 , 0 , 32 ) ;
G_DebugLine ( vStart , vEnd , 1 , 0 , 0 , 1 ) ;
}
}
}
}
void PathSearch : : LoadNodes
(
void
)
{
ai_showroutes = gi . Cvar_Get ( " ai_showroutes " , " 0 " , 0 ) ;
ai_showroutes_distance = gi . Cvar_Get ( " ai_showroutes_distance " , " 1000 " , 0 ) ;
ai_shownodenums = gi . Cvar_Get ( " ai_shownodenums " , " 0 " , 0 ) ;
ai_shownode = gi . Cvar_Get ( " ai_shownode " , " 0 " , 0 ) ;
ai_showallnode = gi . Cvar_Get ( " ai_showallnode " , " 0 " , 0 ) ;
ai_showpath = gi . Cvar_Get ( " ai_showpath " , " 0 " , 0 ) ;
ai_fallheight = gi . Cvar_Get ( " ai_fallheight " , " 96 " , 0 ) ;
ai_debugpath = gi . Cvar_Get ( " ai_debugpath " , " 0 " , 0 ) ;
ai_pathchecktime = gi . Cvar_Get ( " ai_pathchecktime " , " 1.5 " , CVAR_CHEAT ) ;
ai_pathcheckdist = gi . Cvar_Get ( " ai_pathcheckdist " , " 4096 " , CVAR_CHEAT ) ;
ArchiveLoadNodes ( ) ;
}
void PathSearch : : CreatePaths
(
void
)
{
int i ;
int j ;
int x ;
int y ;
PathNode * node ;
Vector start ;
Vector end ;
gentity_t * ent ;
int t1 ;
int t2 ;
if ( m_bNodesloaded )
return ;
if ( ! nodecount )
{
m_bNodesloaded = true ;
return ;
}
m_NodeCheckFailed = false ;
gi . DPrintf ( " *********************************** \n "
" *********************************** \n "
" \n "
" Creating paths... \n "
" \n "
" *********************************** \n "
" *********************************** \n " ) ;
t1 = gi . Milliseconds ( ) ;
for ( i = 0 , ent = g_entities ; i < game . maxentities ; i + + , ent + + )
{
if ( ent - > entity & & ent - > entity - > IsSubclassOfDoor ( ) )
gi . UnlinkEntity ( ent ) ;
}
for ( x = 0 ; x < PATHMAP_GRIDSIZE ; x + + )
{
for ( y = 0 ; y < PATHMAP_GRIDSIZE ; y + + )
{
MapCell * cell = & PathMap [ x ] [ y ] ;
cell - > nodes = ( short * ) gi . Malloc ( PATHMAP_CELLSIZE ) ;
cell - > numnodes = 0 ;
memset ( cell - > nodes , 0 , PATHMAP_CELLSIZE ) ;
}
}
for ( i = 0 ; i < nodecount ; i + + )
{
node = pathnodes [ i ] ;
start = node - > origin + Vector ( 0 , 0 , 36.0f ) ;
end = node - > origin - Vector ( 0 , 0 , 2048.0f ) ;
trace_t trace = G_Trace ( start ,
PLAYER_BASE_MIN ,
PLAYER_BASE_MAX ,
end ,
NULL ,
MASK_PATHSOLID ,
qfalse ,
" droptofloor " ) ;
node - > origin = trace . endpos ;
node - > centroid = trace . endpos ;
if ( ! ( node - > nodeflags & PATH_DONT_LINK ) )
{
for ( j = i - 1 ; j > = 0 ; j - - )
{
PathNode * node2 = pathnodes [ j ] ;
if ( node2 - > origin = = node - > origin )
{
Com_Printf ( " ^~^~^ Duplicate node at (%.2f %.2f %.2f) not linked \n " , node - > origin [ 0 ] , node - > origin [ 1 ] , node - > origin [ 2 ] ) ;
node - > nodeflags | = PATH_DONT_LINK ;
break ;
}
}
if ( ! ( node - > nodeflags & PATH_DONT_LINK ) )
node - > Child = ( pathway_t * ) gi . Malloc ( sizeof ( pathway_t ) * PATHMAP_NODES ) ;
}
}
for ( i = 0 ; i < nodecount ; i + + )
{
node = pathnodes [ i ] ;
if ( node - > nodeflags & PATH_DONT_LINK )
continue ;
AddNode ( node ) ;
}
for ( i = 0 ; i < nodecount ; i + + )
{
node = pathnodes [ i ] ;
if ( node - > nodeflags & PATH_DONT_LINK )
continue ;
Connect ( node ) ;
}
for ( i = 0 , ent = g_entities ; i < game . maxentities ; i + + , ent + + )
{
if ( ent - > entity & & ent - > entity - > IsSubclassOfDoor ( ) )
ent - > entity - > link ( ) ;
}
gi . DPrintf ( " \n Saving path nodes to '%s' \n " , level . m_pathfile . c_str ( ) ) ;
Com_Printf ( " Archiving \n " ) ;
ArchiveSaveNodes ( ) ;
m_bNodesloaded = true ;
Com_Printf ( " done. \n " ) ;
t2 = gi . Milliseconds ( ) ;
Com_Printf ( " Path connection: %5.2f seconds \n " , ( t2 - t1 ) / 1000.0f ) ;
Com_Printf ( " Number of nodes: %d \n " , nodecount ) ;
gi . ClearResource ( ) ;
if ( g_nodecheck - > integer & & m_NodeCheckFailed )
{
gi . Error ( ERR_DROP , " Node check failed " ) ;
}
}
void * PathSearch : : AllocPathNode
(
void
)
{
if ( bulkNavMemory & & ! m_bNodesloaded )
{
bulkNavMemory - = sizeof ( PathNode ) ;
return bulkNavMemory ;
}
else
{
return gi . Malloc ( sizeof ( PathNode ) ) ;
}
}
void PathSearch : : FreePathNode
(
void * ptr
)
{
if ( ! bulkNavMemory | | m_bNodesloaded )
{
gi . Free ( ptr ) ;
}
}
void PathSearch : : ResetNodes
(
void
)
{
int i ;
int x ;
int y ;
m_LoadIndex = - 1 ;
m_bNodesloaded = false ;
if ( ! startBulkNavMemory )
{
for ( x = PATHMAP_GRIDSIZE - 1 ; x > = 0 ; x - - )
{
for ( y = PATHMAP_GRIDSIZE - 1 ; y > = 0 ; y - - )
{
if ( PathMap [ x ] [ y ] . nodes )
gi . Free ( PathMap [ x ] [ y ] . nodes ) ;
}
}
for ( i = 0 ; i < nodecount ; i + + )
{
if ( pathnodes [ i ] - > Child )
gi . Free ( pathnodes [ i ] - > Child ) ;
}
}
for ( x = PATHMAP_GRIDSIZE - 1 ; x > = 0 ; x - - )
{
for ( y = PATHMAP_GRIDSIZE - 1 ; y > = 0 ; y - - )
{
PathMap [ x ] [ y ] . numnodes = 0 ;
PathMap [ x ] [ y ] . nodes = NULL ;
}
}
for ( i = 0 ; i < nodecount ; i + + )
{
delete pathnodes [ i ] ;
pathnodes [ i ] = NULL ;
}
nodecount = 0 ;
// Free the bulk nav' memory
if ( startBulkNavMemory )
{
gi . Free ( startBulkNavMemory ) ;
bulkNavMemory = NULL ;
startBulkNavMemory = NULL ;
}
}
PathInfo * PathSearch : : GeneratePath
(
PathInfo * path
)
{
PathNode * ParentNode ;
pathway_t * pathway ;
float dist ;
float dir [ 2 ] ;
PathInfo * current_path ;
current_path = path ;
dir [ 0 ] = path_end [ 0 ] - Node - > m_PathPos [ 0 ] ;
dir [ 1 ] = path_end [ 1 ] - Node - > m_PathPos [ 1 ] ;
dist = VectorNormalize2D ( dir ) ;
total_dist = dist + Node - > g ;
path - > point [ 0 ] = path_end [ 0 ] ;
path - > point [ 1 ] = path_end [ 1 ] ;
path - > point [ 2 ] = path_end [ 2 ] ;
ParentNode = Node - > Parent ;
if ( ParentNode )
{
pathway = & ParentNode - > Child [ Node - > pathway ] ;
path - > dir [ 0 ] = path_end [ 0 ] - pathway - > pos2 [ 0 ] ;
path - > dir [ 1 ] = path_end [ 1 ] - pathway - > pos2 [ 1 ] ;
path - > dist = VectorNormalize2D ( path - > dir ) ;
if ( path - > dist )
{
path - > bAccurate = false ;
current_path = path + 1 ;
}
if ( pathway - > dist )
{
VectorCopy ( pathway - > pos2 , current_path - > point ) ;
current_path - > dir [ 0 ] = pathway - > dir [ 0 ] ;
current_path - > dir [ 1 ] = pathway - > dir [ 1 ] ;
current_path - > dist = pathway - > dist ;
current_path - > bAccurate = true ;
current_path + + ;
}
for ( Node = ParentNode , ParentNode = ParentNode - > Parent ; ParentNode ! = NULL ; Node = ParentNode , ParentNode = ParentNode - > Parent )
{
pathway = & ParentNode - > Child [ Node - > pathway ] ;
if ( pathway - > dist )
{
VectorCopy ( pathway - > pos2 , current_path - > point ) ;
current_path - > dir [ 0 ] = pathway - > dir [ 0 ] ;
current_path - > dir [ 1 ] = pathway - > dir [ 1 ] ;
current_path - > dist = pathway - > dist ;
current_path - > bAccurate = true ;
current_path + + ;
}
}
VectorCopy ( pathway - > pos1 , current_path - > point ) ;
current_path - > dir [ 0 ] = path_startdir [ 0 ] ;
current_path - > dir [ 1 ] = path_startdir [ 1 ] ;
current_path - > dist = Node - > g ;
}
else
{
path - > dir [ 0 ] = path_totaldir [ 0 ] ;
path - > dir [ 1 ] = path_totaldir [ 1 ] ;
path - > dist = Node - > h ;
}
if ( current_path - > dist )
{
current_path - > bAccurate = false ;
current_path + + ;
VectorCopy ( path_start , current_path - > point ) ;
current_path - > dist = 0 ;
VectorClear2D ( current_path - > dir ) ;
}
current_path - > bAccurate = false ;
return current_path ;
}
PathInfo * PathSearch : : GeneratePathNear
(
PathInfo * path
)
{
PathInfo * current_path = path ;
pathway_t * pathway ;
PathNode * ParentNode ;
total_dist = Node - > g ;
VectorCopy ( Node - > m_PathPos , path - > point ) ;
ParentNode = Node - > Parent ;
if ( ParentNode )
{
pathway = & ParentNode - > Child [ Node - > pathway ] ;
if ( pathway - > dist )
{
VectorCopy ( pathway - > pos2 , path - > point ) ;
path - > dir [ 0 ] = pathway - > dir [ 0 ] ;
path - > dir [ 1 ] = pathway - > dir [ 1 ] ;
path - > dist = pathway - > dist ;
current_path - > bAccurate = true ;
current_path + + ;
}
for ( Node = ParentNode , ParentNode = ParentNode - > Parent ; ParentNode ! = NULL ; Node = ParentNode , ParentNode = ParentNode - > Parent )
{
pathway = & ParentNode - > Child [ Node - > pathway ] ;
if ( pathway - > dist )
{
VectorCopy ( pathway - > pos2 , current_path - > point ) ;
current_path - > dir [ 0 ] = pathway - > dir [ 0 ] ;
current_path - > dir [ 1 ] = pathway - > dir [ 1 ] ;
current_path - > dist = pathway - > dist ;
current_path - > bAccurate = true ;
current_path + + ;
}
}
VectorCopy ( pathway - > pos1 , current_path - > point ) ;
current_path - > dir [ 0 ] = path_startdir [ 0 ] ;
current_path - > dir [ 1 ] = path_startdir [ 1 ] ;
current_path - > dist = Node - > g ;
}
else
{
path - > dir [ 0 ] = path_totaldir [ 0 ] ;
path - > dir [ 1 ] = path_totaldir [ 1 ] ;
path - > dist = Node - > h ;
}
if ( current_path - > dist )
{
current_path - > bAccurate = false ;
current_path + + ;
VectorCopy ( path_start , current_path - > point ) ;
current_path - > dist = 0 ;
VectorClear2D ( current_path - > dir ) ;
}
current_path - > bAccurate = false ;
return current_path ;
}
PathInfo * PathSearch : : GeneratePathAway
(
PathInfo * path
)
{
PathInfo * current_path = path ;
pathway_t * pathway ;
PathNode * ParentNode ;
VectorCopy ( Node - > m_PathPos , path - > point ) ;
ParentNode = Node - > Parent ;
if ( ParentNode )
{
pathway = & ParentNode - > Child [ Node - > pathway ] ;
if ( pathway - > dist )
{
VectorCopy ( pathway - > pos2 , path - > point ) ;
path - > dir [ 0 ] = pathway - > dir [ 0 ] ;
path - > dir [ 1 ] = pathway - > dir [ 1 ] ;
path - > dist = pathway - > dist ;
current_path - > bAccurate = true ;
current_path + + ;
}
for ( Node = ParentNode , ParentNode = ParentNode - > Parent ; ParentNode ! = NULL ; Node = ParentNode , ParentNode = ParentNode - > Parent )
{
pathway = & ParentNode - > Child [ Node - > pathway ] ;
if ( pathway - > dist )
{
VectorCopy ( pathway - > pos2 , current_path - > point ) ;
current_path - > dir [ 0 ] = pathway - > dir [ 0 ] ;
current_path - > dir [ 1 ] = pathway - > dir [ 1 ] ;
current_path - > dist = pathway - > dist ;
current_path - > bAccurate = true ;
current_path + + ;
}
}
VectorCopy ( pathway - > pos1 , current_path - > point ) ;
current_path - > dir [ 0 ] = path_startdir [ 0 ] ;
current_path - > dir [ 1 ] = path_startdir [ 1 ] ;
current_path - > dist = Node - > g ;
if ( Node - > g )
{
current_path - > bAccurate = false ;
current_path + + ;
VectorCopy ( path_start , current_path - > point ) ;
current_path - > dist = 0 ;
VectorClear2D ( current_path - > dir ) ;
}
}
else
{
VectorClear2D ( path - > dir ) ;
path - > dist = 0 ;
}
current_path - > bAccurate = false ;
return current_path ;
}
PathNode * PathSearch : : GetSpawnNode
(
ClassDef * cls
)
{
if ( m_bNodesloaded )
{
return pathnodes [ m_LoadIndex + + ] ;
}
else
{
// Otherwise create a new node
return ( PathNode * ) cls - > newInstance ( ) ;
}
}
int PathSearch : : FindPath
(
float * start ,
float * end ,
Entity * ent ,
float maxPath ,
float * vLeashHome ,
float fLeashDistSquared ,
int fallheight
)
{
int i ;
int g ;
PathNode * NewNode ;
pathway_t * pathway ;
PathNode * prev ;
PathNode * next ;
int f ;
vec2_t delta ;
PathNode * to ;
if ( ent )
{
if ( ent - > IsSubclassOfActor ( ) )
{
Node = NearestStartNode ( start , ( SimpleActor * ) ent ) ;
}
else
{
Node = DebugNearestStartNode ( start , ent ) ;
}
}
else
{
Node = DebugNearestStartNode ( start ) ;
}
if ( ! Node )
{
last_error = " couldn't find start node " ;
2023-02-01 00:28:40 +01:00
return 0 ;
2016-03-27 11:49:47 +02:00
}
to = NearestEndNode ( end ) ;
if ( ! to )
{
last_error = " couldn't find end node " ;
2023-02-01 00:28:40 +01:00
return 0 ;
2016-03-27 11:49:47 +02:00
}
total_dist = 9e+11 f ;
if ( ! maxPath )
maxPath = 9e+11 f ;
findFrame + + ;
open = NULL ;
path_startdir [ 0 ] = Node - > origin [ 0 ] - start [ 0 ] ;
path_startdir [ 1 ] = Node - > origin [ 1 ] - start [ 1 ] ;
Node - > g = VectorNormalize2D ( path_startdir ) ;
path_totaldir [ 0 ] = end [ 0 ] - start [ 0 ] ;
path_totaldir [ 1 ] = end [ 1 ] - start [ 1 ] ;
Node - > h = VectorNormalize2D ( path_totaldir ) ;
Node - > inopen = true ;
Node - > Parent = NULL ;
Node - > m_Depth = 3 ;
Node - > m_PathPos = start ;
Node - > findCount = findFrame ;
Node - > PrevNode = NULL ;
Node - > NextNode = NULL ;
open = Node ;
while ( 1 )
{
Node = open ;
Node - > inopen = false ;
open = Node - > NextNode ;
if ( open )
open - > PrevNode = NULL ;
if ( Node = = to )
break ;
for ( i = Node - > numChildren - 1 ; i > = 0 ; i - - )
{
vec2_t vDist ;
pathway = & Node - > Child [ i ] ;
NewNode = pathnodes [ pathway - > node ] ;
if ( vLeashHome )
{
vDist [ 0 ] = pathway - > pos2 [ 0 ] - vLeashHome [ 0 ] ;
vDist [ 1 ] = pathway - > pos2 [ 1 ] - vLeashHome [ 1 ] ;
}
if ( ! vLeashHome | | VectorLength2DSquared ( vDist ) < = fLeashDistSquared )
{
g = ( int ) ( pathway - > dist + Node - > g + 1.0f ) ;
if ( NewNode - > findCount = = findFrame )
{
if ( g > = NewNode - > g )
continue ;
if ( NewNode - > inopen )
{
NewNode - > inopen = false ;
next = NewNode - > NextNode ;
prev = NewNode - > PrevNode ;
if ( next )
next - > PrevNode = prev ;
if ( prev )
prev - > NextNode = next ;
else
open = next ;
}
}
delta [ 0 ] = end [ 0 ] - pathway - > pos2 [ 0 ] ;
delta [ 1 ] = end [ 1 ] - pathway - > pos2 [ 1 ] ;
NewNode - > h = VectorLength2D ( delta ) ;
f = ( int ) ( ( float ) g + NewNode - > h ) ;
if ( f > = maxPath )
{
last_error = " specified path distance exceeded " ;
2023-02-01 00:28:40 +01:00
return 0 ;
2016-03-27 11:49:47 +02:00
}
if ( pathway - > fallheight < = fallheight )
{
NewNode - > f = f ;
NewNode - > pathway = i ;
NewNode - > g = g ;
NewNode - > Parent = Node ;
NewNode - > m_Depth = Node - > m_Depth + 1 ;
NewNode - > inopen = true ;
NewNode - > m_PathPos = pathway - > pos2 ;
NewNode - > findCount = findFrame ;
if ( ! open )
{
NewNode - > NextNode = NULL ;
NewNode - > PrevNode = NULL ;
open = NewNode ;
continue ;
}
if ( open - > f > = f )
{
NewNode - > PrevNode = NULL ;
NewNode - > NextNode = open ;
open - > PrevNode = NewNode ;
open = NewNode ;
continue ;
}
prev = open ;
next = open - > NextNode ;
while ( next & & next - > f < f )
{
prev = next ;
next = next - > NextNode ;
}
NewNode - > NextNode = next ;
if ( next )
next - > PrevNode = NewNode ;
prev - > NextNode = NewNode ;
NewNode - > PrevNode = prev ;
}
}
}
if ( ! open )
{
last_error = " unreachable path " ;
2023-02-01 00:28:40 +01:00
return 0 ;
2016-03-27 11:49:47 +02:00
}
}
path_start = start ;
path_end = end ;
return Node - > m_Depth ;
}
int PathSearch : : FindPathAway
(
float * start ,
float * avoid ,
float * vPreferredDir ,
Entity * ent ,
float fMinSafeDist ,
float * vLeashHome ,
float fLeashDistSquared ,
int fallheight
)
{
int i ;
int g ;
PathNode * NewNode ;
pathway_t * pathway ;
PathNode * prev ;
PathNode * next ;
int f ;
float fBias ;
vec2_t delta ;
float fMinSafeDistSquared = fMinSafeDist * fMinSafeDist ;
if ( ent )
{
if ( ent - > IsSubclassOfActor ( ) )
{
Node = NearestStartNode ( start , ( SimpleActor * ) ent ) ;
}
else
{
Node = DebugNearestStartNode ( start , ent ) ;
}
}
else
{
Node = DebugNearestStartNode ( start ) ;
}
if ( ! Node )
{
last_error = " couldn't find start node " ;
return 0 ;
}
findFrame + + ;
open = NULL ;
path_startdir [ 0 ] = Node - > origin [ 0 ] - start [ 0 ] ;
path_startdir [ 1 ] = Node - > origin [ 1 ] - start [ 1 ] ;
delta [ 0 ] = start [ 0 ] - avoid [ 0 ] ;
delta [ 1 ] = start [ 1 ] - avoid [ 1 ] ;
fBias = VectorLength2D ( vPreferredDir ) ;
Node - > inopen = true ;
Node - > g = VectorNormalize2D ( path_startdir ) ;
Node - > h = fMinSafeDist - VectorNormalize2D ( delta ) ;
Node - > h + = fBias - DotProduct2D ( vPreferredDir , delta ) ;
Node - > Parent = NULL ;
Node - > m_Depth = 2 ;
Node - > findCount = findFrame ;
Node - > PrevNode = NULL ;
Node - > NextNode = NULL ;
Node - > m_PathPos = start ;
open = Node ;
while ( 1 )
{
Node = open ;
Node - > inopen = false ;
open = Node - > NextNode ;
if ( open )
open - > PrevNode = NULL ;
delta [ 0 ] = Node - > m_PathPos [ 0 ] - avoid [ 0 ] ;
delta [ 1 ] = Node - > m_PathPos [ 1 ] - avoid [ 1 ] ;
if ( VectorLength2DSquared ( delta ) > = fMinSafeDistSquared )
break ;
for ( i = Node - > numChildren - 1 ; i > = 0 ; i - - )
{
vec2_t vDist ;
pathway = & Node - > Child [ i ] ;
NewNode = pathnodes [ pathway - > node ] ;
if ( vLeashHome )
{
vDist [ 0 ] = pathway - > pos2 [ 0 ] - vLeashHome [ 0 ] ;
vDist [ 1 ] = pathway - > pos2 [ 1 ] - vLeashHome [ 1 ] ;
}
if ( ! vLeashHome | | VectorLength2DSquared ( vDist ) < = fLeashDistSquared )
{
g = ( int ) ( pathway - > dist + Node - > g + 1.0f ) ;
if ( NewNode - > findCount = = findFrame )
{
if ( g > = NewNode - > g )
continue ;
if ( NewNode - > inopen )
{
NewNode - > inopen = false ;
next = NewNode - > NextNode ;
prev = NewNode - > PrevNode ;
if ( next )
next - > PrevNode = prev ;
if ( prev )
prev - > NextNode = next ;
else
open = next ;
}
}
delta [ 0 ] = pathway - > pos2 [ 0 ] - avoid [ 0 ] ;
delta [ 1 ] = pathway - > pos2 [ 1 ] - avoid [ 1 ] ;
NewNode - > h = fMinSafeDist - VectorNormalize2D ( delta ) ;
f = NewNode - > h + fBias - DotProduct2D ( vPreferredDir , delta ) ;
NewNode - > h + = f ;
if ( pathway - > fallheight < = fallheight )
{
NewNode - > Parent = Node ;
NewNode - > m_Depth = Node - > m_Depth + 1 ;
NewNode - > g = g ;
NewNode - > pathway = i ;
NewNode - > inopen = true ;
NewNode - > m_PathPos = pathway - > pos2 ;
NewNode - > findCount = findFrame ;
NewNode - > f = f ;
if ( ! open )
{
NewNode - > NextNode = NULL ;
NewNode - > PrevNode = NULL ;
open = NewNode ;
continue ;
}
if ( open - > f > = f )
{
NewNode - > PrevNode = NULL ;
NewNode - > NextNode = open ;
open - > PrevNode = NewNode ;
open = NewNode ;
continue ;
}
prev = open ;
next = open - > NextNode ;
while ( next & & next - > f < f )
{
prev = next ;
next = next - > NextNode ;
}
NewNode - > NextNode = next ;
if ( next )
next - > PrevNode = NewNode ;
prev - > NextNode = NewNode ;
NewNode - > PrevNode = prev ;
}
}
}
if ( ! open )
{
last_error = " unreachable path " ;
2023-02-01 00:28:40 +01:00
return 0 ;
2016-03-27 11:49:47 +02:00
}
}
path_start = start ;
return Node - > m_Depth ;
}
int PathSearch : : FindPathNear
(
float * start ,
float * end ,
Entity * ent ,
float maxPath ,
float fRadiusSquared ,
float * vLeashHome ,
float fLeashDistSquared ,
int fallheight
)
{
int i ;
int g ;
PathNode * NewNode ;
pathway_t * pathway ;
PathNode * prev ;
PathNode * next ;
int f ;
vec2_t dir ;
vec2_t delta ;
if ( ent )
{
if ( ent - > IsSubclassOfActor ( ) )
{
Node = NearestStartNode ( start , ( SimpleActor * ) ent ) ;
}
else
{
Node = DebugNearestStartNode ( start , ent ) ;
}
}
else
{
Node = DebugNearestStartNode ( start ) ;
}
if ( ! Node )
{
last_error = " no start node " ;
return 0 ;
}
total_dist = 9e11 f ;
if ( ! maxPath )
maxPath = 9e11 f ;
findFrame + + ;
open = NULL ;
path_startdir [ 0 ] = Node - > origin [ 0 ] - start [ 0 ] ;
path_startdir [ 1 ] = Node - > origin [ 1 ] - start [ 1 ] ;
dir [ 0 ] = end [ 0 ] - start [ 0 ] ;
dir [ 1 ] = end [ 1 ] - start [ 1 ] ;
Node - > inopen = true ;
Node - > g = VectorNormalize2D ( path_startdir ) ;
Node - > h = VectorNormalize2D ( delta ) ;
Node - > Parent = NULL ;
Node - > m_Depth = 3 ;
Node - > findCount = findFrame ;
Node - > PrevNode = NULL ;
Node - > NextNode = NULL ;
Node - > m_PathPos = start ;
open = Node ;
while ( 1 )
{
Node = open ;
Node - > inopen = false ;
open = Node - > NextNode ;
if ( open )
open - > PrevNode = NULL ;
delta [ 0 ] = end [ 0 ] - Node - > m_PathPos [ 0 ] ;
delta [ 1 ] = end [ 1 ] - Node - > m_PathPos [ 1 ] ;
if ( fRadiusSquared > = VectorLength2DSquared ( delta ) )
break ;
for ( i = Node - > numChildren - 1 ; i > = 0 ; i - - )
{
pathway = & Node - > Child [ i ] ;
NewNode = pathnodes [ pathway - > node ] ;
g = ( int ) ( pathway - > dist + Node - > g + 1.0f ) ;
if ( NewNode - > findCount = = findFrame )
{
if ( g > = NewNode - > g )
continue ;
if ( NewNode - > inopen )
{
NewNode - > inopen = false ;
next = NewNode - > NextNode ;
prev = NewNode - > PrevNode ;
if ( next )
next - > PrevNode = prev ;
if ( prev )
prev - > NextNode = next ;
else
open = next ;
}
}
delta [ 0 ] = end [ 0 ] - pathway - > pos2 [ 0 ] ;
delta [ 1 ] = end [ 1 ] - pathway - > pos2 [ 1 ] ;
NewNode - > h = VectorLength2D ( delta ) ;
f = ( int ) ( ( float ) g + NewNode - > h ) ;
if ( f > = maxPath )
{
last_error = " specified path distance exceeded " ;
2023-02-01 00:28:40 +01:00
return 0 ;
2016-03-27 11:49:47 +02:00
}
if ( pathway - > fallheight < = fallheight )
{
NewNode - > f = f ;
NewNode - > pathway = i ;
NewNode - > g = g ;
NewNode - > Parent = Node ;
NewNode - > m_Depth = Node - > m_Depth + 1 ;
NewNode - > inopen = true ;
NewNode - > m_PathPos = pathway - > pos2 ;
NewNode - > findCount = findFrame ;
if ( ! open )
{
NewNode - > NextNode = NULL ;
NewNode - > PrevNode = NULL ;
open = NewNode ;
continue ;
}
if ( open - > f > = f )
{
NewNode - > PrevNode = NULL ;
NewNode - > NextNode = open ;
open - > PrevNode = NewNode ;
open = NewNode ;
continue ;
}
prev = open ;
next = open - > NextNode ;
while ( next & & next - > f < f )
{
prev = next ;
next = next - > NextNode ;
}
NewNode - > NextNode = next ;
if ( next )
next - > PrevNode = NewNode ;
prev - > NextNode = NewNode ;
NewNode - > PrevNode = prev ;
}
}
if ( ! open )
{
last_error = " unreachable path " ;
2023-02-01 00:28:40 +01:00
return 0 ;
2016-03-27 11:49:47 +02:00
}
}
path_start = start ;
path_end = end ;
return Node - > m_Depth ;
}
2018-09-17 23:50:38 +02:00
int node_compare ( const void * pe1 , const void * pe2 )
{
nodeinfo * Pe1 = ( nodeinfo * ) pe1 ;
nodeinfo * Pe2 = ( nodeinfo * ) pe2 ;
int iConcealment ;
iConcealment = ( Pe1 - > pNode - > nodeflags & 0xB0 ) ! = 0 ;
if ( Pe2 - > pNode - > nodeflags & 0xB0 )
- - iConcealment ;
return ( ( Pe1 - > fDistSquared )
+ ( iConcealment < < 23 )
+ ( ( ( Pe1 - > pNode - > nodeflags & 8 ) - ( Pe2 - > pNode - > nodeflags & 8 ) ) < < 21 )
- ( Pe2 - > fDistSquared ) ) ;
}
2016-03-27 11:49:47 +02:00
PathNode * PathSearch : : FindCornerNodeForWall
(
float * start ,
float * end ,
SimpleActor * ent ,
float maxPath ,
float * plane
)
{
2018-09-17 23:50:38 +02:00
PathNode * ParentNode ;
PathNode * OpenNode ;
int i ;
Node = NearestStartNode ( start , ent ) ;
if ( ! Node )
{
last_error = " couldn't find start node " ;
return NULL ;
}
if ( DotProduct ( start , plane ) - plane [ 3 ] < 0.0 )
{
last_error = " starting point is already behind the wall " ;
return NULL ;
}
if ( DotProduct ( plane , end ) - plane [ 3 ] > 0.0 )
{
last_error = " end point is in front of the wall " ;
return NULL ;
}
total_dist = 1.0e12 f ;
if ( maxPath = = 0.0 )
maxPath = 1.0e12 f ;
findFrame + + ;
open = NULL ;
VectorSub2D ( Node - > origin , start , path_startdir ) ;
Node - > g = VectorNormalize2D ( path_startdir ) ;
VectorSub2D ( end , start , path_totaldir ) ;
Node - > h = VectorNormalize2D ( path_totaldir ) ;
Node - > inopen = true ;
Node - > Parent = NULL ;
Node - > m_Depth = 3 ;
Node - > m_PathPos = start ;
Node - > findCount = findFrame ;
Node - > PrevNode = 0 ;
Node - > NextNode = 0 ;
2019-08-18 22:06:49 +02:00
OpenNode = Node ;
2018-09-17 23:50:38 +02:00
open = Node ;
if ( ! open )
{
last_error = " unreachable path " ;
return NULL ;
}
while ( true )
{
Node = OpenNode ;
Node - > inopen = false ;
open = Node - > NextNode ;
if ( open )
{
open - > PrevNode = NULL ;
}
ParentNode = Node - > Parent ;
if ( ParentNode
& & DotProduct ( plane , Node - > m_PathPos ) - plane [ 3 ] < 0.0 )
{
vec2_t delta ;
VectorSub2D ( ParentNode - > m_PathPos , start , delta ) ;
2019-08-18 22:06:49 +02:00
if ( VectorLength2DSquared ( delta ) < Square ( 16 ) )
2018-09-17 23:50:38 +02:00
ParentNode = Node ;
return ParentNode ;
}
i = Node - > numChildren ;
if ( i )
break ;
2019-08-18 22:06:49 +02:00
weird_lbl :
2018-09-17 23:50:38 +02:00
OpenNode = open ;
if ( ! OpenNode )
{
last_error = " unreachable path " ;
return NULL ;
}
2019-08-18 22:06:49 +02:00
}
int f , g , h ;
while ( true )
{
pathway_t * pathway = & Node - > Child [ - - i ] ;
PathNode * pSomeNode = PathSearch : : pathnodes [ pathway - > node ] ;
g = ( pathway - > dist + Node - > g + 1.0 ) ;
if ( pSomeNode - > findCount = = PathSearch : : findFrame )
{
if ( g > = pSomeNode - > g )
{
if ( i = = 0 )
goto weird_lbl ;
continue ;
}
if ( pSomeNode - > inopen )
{
pSomeNode - > inopen = false ;
if ( pSomeNode - > NextNode )
pSomeNode - > NextNode - > PrevNode = pSomeNode - > PrevNode ;
if ( pSomeNode - > PrevNode )
pSomeNode - > PrevNode - > NextNode = pSomeNode - > NextNode ;
else
PathSearch : : open = pSomeNode - > NextNode ;
}
}
vec2_t vDelta2 ;
VectorSub2D ( end , pathway - > pos1 , vDelta2 ) ;
pSomeNode - > h = h = VectorLength2D ( vDelta2 ) ;
f = ( h + g ) ;
if ( f > = maxPath )
break ;
pSomeNode - > f = f ;
pSomeNode - > pathway = i ;
pSomeNode - > g = g ;
pSomeNode - > Parent = Node ;
pSomeNode - > inopen = true ;
pSomeNode - > m_PathPos = pathway - > pos2 ;
pSomeNode - > findCount = PathSearch : : findFrame ;
pSomeNode - > m_Depth = Node - > m_Depth + 1 ;
if ( ! PathSearch : : open )
{
pSomeNode - > NextNode = NULL ;
pSomeNode - > PrevNode = NULL ;
PathSearch : : open = pSomeNode ;
if ( i = = 0 )
goto weird_lbl ;
continue ;
}
if ( PathSearch : : open - > f = = f )
{
pSomeNode - > PrevNode = NULL ;
pSomeNode - > NextNode = PathSearch : : open ;
PathSearch : : open - > PrevNode = pSomeNode ;
PathSearch : : open = pSomeNode ;
if ( i = = 0 )
goto weird_lbl ;
continue ;
}
PathNode * pNextOpenNode = PathSearch : : open - > NextNode ;
if ( pNextOpenNode )
{
if ( f > pNextOpenNode - > f )
{
do
{
pNextOpenNode = pNextOpenNode - > NextNode ;
if ( ! pNextOpenNode )
break ;
} while ( f > pNextOpenNode - > f ) ;
}
}
pSomeNode - > NextNode = pNextOpenNode ;
if ( pNextOpenNode )
pNextOpenNode - > PrevNode = pSomeNode ;
pNextOpenNode - > NextNode = pSomeNode ;
pSomeNode - > PrevNode = pNextOpenNode ;
if ( i = = 0 )
goto weird_lbl ;
}
PathSearch : : last_error = " specified path distance exceeded " ;
return NULL ;
2016-03-27 11:49:47 +02:00
}
PathNode * PathSearch : : FindCornerNodeForExactPath
(
2019-08-13 03:12:07 +02:00
SimpleActor * pSelf ,
2016-03-27 11:49:47 +02:00
Sentient * enemy ,
float fMaxPath
)
{
2019-08-13 03:12:07 +02:00
PathNode * pPathNode [ 4096 ] ;
if ( ! PathSearch : : FindPath ( enemy - > origin , pSelf - > origin , pSelf , fMaxPath , 0 , 0.0 , 100 ) )
return NULL ;
2023-01-30 00:23:47 +01:00
size_t iDepth = 0 ;
2019-08-13 03:12:07 +02:00
for ( PathNode * pParentNode = Node - > Parent ; pParentNode ; pParentNode = pParentNode - > Parent , iDepth + + )
{
pPathNode [ iDepth ] = pParentNode ;
}
Node = pPathNode [ iDepth - 1 ] ;
if ( iDepth = = 0 )
{
return NULL ;
}
size_t i ;
for ( i = 0 ; i < iDepth ; i + = 2 )
{
if ( ! G_SightTrace (
pSelf - > EyePosition ( ) ,
vec_zero ,
vec_zero ,
pSelf - > EyePosition ( ) - pSelf - > origin + pPathNode [ i ] - > m_PathPos ,
pSelf ,
enemy ,
0x2040B19 ,
0 ,
" FindCornerNodeFoExactPath 1 " ) )
{
break ;
}
}
2023-01-30 00:23:47 +01:00
size_t index = i - 1 ;
2019-08-13 03:12:07 +02:00
if ( index < iDepth )
{
if ( index )
{
if ( ! G_SightTrace (
pSelf - > EyePosition ( ) ,
vec_zero ,
vec_zero ,
pSelf - > EyePosition ( ) - pSelf - > origin + pPathNode [ i ] - > m_PathPos ,
pSelf ,
enemy ,
0x2040B19 ,
0 ,
" FindCornerNodeFoExactPath 2 " ) )
{
index - - ;
}
}
}
else
{
index = iDepth - 1 ;
}
return pPathNode [ index ] ;
2016-03-27 11:49:47 +02:00
}
int PathSearch : : FindPotentialCover
(
SimpleActor * pEnt ,
Vector & vPos ,
Entity * pEnemy ,
PathNode * * ppFoundNodes ,
int iMaxFind
)
{
2018-09-17 23:50:38 +02:00
Actor * pSelf = ( Actor * ) pEnt ;
PathNode * pNode ;
Vector delta ;
int nNodes = 0 ;
nodeinfo nodes [ MAX_PATHNODES ] ;
for ( int i = 0 ; i < nodecount ; i + + )
{
pNode = pathnodes [ i ] ;
if ( pNode & & pNode - > nodeflags & AI_SNIPER )
{
if ( pNode - > pLastClaimer = = pSelf | | ( pNode - > iAvailableTime & & level . inttime > = pNode - > iAvailableTime ) | | ( pNode - > pLastClaimer = = NULL ) )
{
delta = pNode - > origin - pSelf - > m_vHome ;
if ( delta . lengthSquared ( ) < = pSelf - > m_fLeashSquared )
{
delta = pNode - > origin - pEnemy - > origin ;
if ( delta . lengthSquared ( ) > = pSelf - > m_fMinDistanceSquared & & delta . lengthSquared ( ) < = pSelf - > m_fMaxDistanceSquared )
{
delta = pNode - > origin - pSelf - > origin ;
nodes [ nNodes ] . pNode = pNode ;
nodes [ nNodes ] . fDistSquared = delta . lengthSquared ( ) ;
nNodes + + ;
}
}
}
}
}
if ( nNodes )
{
qsort ( nodes , nNodes , sizeof ( nodeinfo ) , node_compare ) ;
if ( nNodes > iMaxFind )
nNodes = iMaxFind ;
if ( nNodes > 0 )
{
pNode = ppFoundNodes [ nNodes - 1 ] ;
for ( int i = 0 ; i < nNodes ; i + + )
{
pNode = nodes [ i ] . pNode ;
pNode - - ;
}
}
}
return nNodes ;
2016-03-27 11:49:47 +02:00
}
void PathSearch : : PlayerCover
(
Player * pPlayer
)
{
int i ;
PathNode * node ;
Vector delta ;
Entity * pOwner ;
for ( i = 0 ; i < nodecount ; i + + )
{
node = pathnodes [ i ] ;
if ( ! node | | ! ( node - > nodeflags & AI_COVERFLAGS ) )
continue ;
pOwner = node - > GetClaimHolder ( ) ;
delta = node - > origin - pPlayer - > origin ;
// Check if we need to cover
if ( VectorLengthSquared ( delta ) > 2304.0f )
{
if ( pOwner = = pPlayer )
node - > Relinquish ( ) ;
continue ;
}
if ( pOwner ! = pPlayer )
{
if ( pOwner )
pOwner - > PathnodeClaimRevoked ( node ) ;
// Player claim the node
node - > Claim ( pPlayer ) ;
}
}
}
PathNode * PathSearch : : FindNearestCover
(
SimpleActor * pEnt ,
Vector & vPos ,
Entity * pEnemy
)
{
2019-08-18 22:06:49 +02:00
// not found in ida
2016-03-27 11:49:47 +02:00
return NULL ;
}
2019-08-18 22:06:49 +02:00
2016-03-27 11:49:47 +02:00
PathNode * PathSearch : : FindNearestSniperNode
(
SimpleActor * pEnt ,
Vector & vPos ,
Entity * pEnemy
)
{
2018-09-17 23:50:38 +02:00
Actor * pSelf = ( Actor * ) pEnt ;
PathNode * pNode ;
Vector delta ;
int nNodes = 0 ;
nodeinfo nodes [ MAX_PATHNODES ] ;
for ( int i = 0 ; i < nodecount ; i + + )
{
pNode = pathnodes [ i ] ;
if ( pNode & & pNode - > nodeflags & AI_SNIPER )
{
if ( pNode - > pLastClaimer = = pSelf | | ( pNode - > iAvailableTime & & level . inttime > = pNode - > iAvailableTime ) | | ( pNode - > pLastClaimer = = NULL ) )
{
delta = pNode - > origin - pSelf - > m_vHome ;
if ( delta . lengthSquared ( ) < = pSelf - > m_fLeashSquared )
{
delta = pNode - > origin - pEnemy - > origin ;
if ( delta . lengthSquared ( ) > = pSelf - > m_fMinDistanceSquared & & delta . lengthSquared ( ) < = pSelf - > m_fMaxDistanceSquared )
{
delta = pNode - > origin - pSelf - > origin ;
nodes [ nNodes ] . pNode = pNode ;
nodes [ nNodes ] . fDistSquared = delta . lengthSquared ( ) ;
nNodes + + ;
}
}
}
}
}
if ( nNodes = = 0 )
{
return NULL ;
}
qsort ( nodes , nNodes , sizeof ( nodeinfo ) , node_compare ) ;
if ( nNodes < = 0 )
return NULL ;
for ( int i = 0 ; i < nNodes ; i + + )
{
pNode = nodes [ i ] . pNode ;
if ( pSelf - > CanSeeFrom ( pSelf - > EyePosition ( ) + pNode - > origin , pEnemy ) )
{
return pNode ;
}
pNode - > iAvailableTime = level . inttime + 5000 ;
pNode - > pLastClaimer = NULL ;
}
2016-03-27 11:49:47 +02:00
return NULL ;
}
int PathSearch : : NearestNodeSetup
(
vec3_t pos ,
MapCell * cell ,
int * nodes ,
vec3_t * deltas
)
{
vec3_t delta ;
PathNode * node ;
float dist ;
int n = 0 ;
int i ;
int j ;
float node_dist [ 128 ] ;
int node_count ;
node_count = cell - > numnodes ;
for ( i = 0 ; i < node_count ; i + + )
{
node = pathnodes [ cell - > nodes [ i ] ] ;
if ( pos [ 2 ] > node - > origin [ 2 ] + 94.0f )
continue ;
if ( node - > origin [ 2 ] > pos [ 2 ] + 94.0f )
continue ;
delta [ 0 ] = node - > origin [ 0 ] - pos [ 0 ] ;
delta [ 1 ] = node - > origin [ 1 ] - pos [ 1 ] ;
delta [ 2 ] = node - > origin [ 2 ] - pos [ 2 ] ;
VectorCopy ( delta , deltas [ i ] ) ;
dist = VectorLengthSquared ( delta ) ;
for ( j = n ; j > 0 ; j - - )
{
if ( dist > = node_dist [ j - 1 ] )
break ;
node_dist [ j ] = node_dist [ j - 1 ] ;
nodes [ j ] = nodes [ j - 1 ] ;
}
n + + ;
nodes [ j ] = i ;
node_dist [ j ] = dist ;
}
return n ;
}
void PathSearch : : Init
(
void
)
{
ai_showroutes = gi . Cvar_Get ( " ai_showroutes " , " 0 " , 0 ) ;
ai_showroutes_distance = gi . Cvar_Get ( " ai_showroutes_distance " , " 1000 " , 0 ) ;
ai_shownodenums = gi . Cvar_Get ( " ai_shownodenums " , " 0 " , 0 ) ;
ai_shownode = gi . Cvar_Get ( " ai_shownode " , " 0 " , 0 ) ;
ai_showallnode = gi . Cvar_Get ( " ai_showallnode " , " 0 " , 0 ) ;
ai_showpath = gi . Cvar_Get ( " ai_showpath " , " 0 " , 0 ) ;
ai_fallheight = gi . Cvar_Get ( " ai_fallheight " , " 4096 " , 0 ) ;
ai_debugpath = gi . Cvar_Get ( " ai_debugpath " , " 0 " , 0 ) ;
ai_pathchecktime = gi . Cvar_Get ( " ai_pathchecktime " , " 1.5 " , CVAR_CHEAT ) ;
ai_pathcheckdist = gi . Cvar_Get ( " ai_pathcheckdist " , " 4096 " , CVAR_CHEAT ) ;
}
Event EV_AttractiveNode_GetPriority
(
" priority " ,
EV_DEFAULT ,
NULL ,
NULL ,
" Get the node priority " ,
EV_GETTER
) ;
Event EV_AttractiveNode_SetPriority
(
" priority " ,
EV_DEFAULT ,
" i " ,
" priority " ,
" Set the node priority " ,
EV_SETTER
) ;
Event EV_AttractiveNode_GetDistance
(
" max_dist " ,
EV_DEFAULT ,
NULL ,
NULL ,
" Get the max distance for this node " ,
EV_GETTER
) ;
Event EV_AttractiveNode_SetDistance
(
" max_dist " ,
EV_DEFAULT ,
" f " ,
" max_dist " ,
" Set the max distance for this node to be attracted, -1 for unlimited distance. " ,
EV_SETTER
) ;
Event EV_AttractiveNode_GetStayTime
(
" stay_time " ,
EV_DEFAULT ,
NULL ,
NULL ,
" Get the max stay time for this node " ,
EV_GETTER
) ;
Event EV_AttractiveNode_SetStayTime
(
" stay_time " ,
EV_DEFAULT ,
" f " ,
" stay_time " ,
" Set the maximum stay time AI will stay on this node " ,
EV_SETTER
) ;
Event EV_AttractiveNode_GetRespawnTime
(
" respawn_time " ,
EV_DEFAULT ,
NULL ,
NULL ,
" Get the how much time will this node re-attract already attracted AIs " ,
EV_GETTER
) ;
Event EV_AttractiveNode_SetRespawnTime
(
" respawn_time " ,
EV_DEFAULT ,
" f " ,
" respawn_time " ,
" Set the how much time will this node re-attract already attracted AIs. The minimum required value is 1, otherwise AI will get stuck. " ,
EV_SETTER
) ;
Event EV_AttractiveNode_GetTeam
(
" team " ,
EV_DEFAULT ,
NULL ,
NULL ,
" Get the attractive node team. 'none' for no team. " ,
EV_GETTER
) ;
Event EV_AttractiveNode_SetTeam
(
" team " ,
EV_DEFAULT ,
" s " ,
" team " ,
" Set the attractive node team. 'none' for no team. " ,
EV_SETTER
) ;
Event EV_AttractiveNode_SetUse
(
" setuse " ,
EV_DEFAULT ,
" b " ,
" use " ,
" Set if AI should use or not "
) ;
CLASS_DECLARATION ( SimpleArchivedEntity , AttractiveNode , NULL )
{
{ & EV_AttractiveNode_GetPriority , & AttractiveNode : : GetPriority } ,
{ & EV_AttractiveNode_SetPriority , & AttractiveNode : : SetPriority } ,
{ & EV_AttractiveNode_GetDistance , & AttractiveNode : : GetDistance } ,
{ & EV_AttractiveNode_SetDistance , & AttractiveNode : : SetDistance } ,
{ & EV_AttractiveNode_GetStayTime , & AttractiveNode : : GetStayTime } ,
{ & EV_AttractiveNode_SetStayTime , & AttractiveNode : : SetStayTime } ,
{ & EV_AttractiveNode_GetRespawnTime , & AttractiveNode : : GetRespawnTime } ,
{ & EV_AttractiveNode_SetRespawnTime , & AttractiveNode : : SetRespawnTime } ,
{ & EV_AttractiveNode_GetTeam , & AttractiveNode : : GetTeam } ,
{ & EV_AttractiveNode_SetTeam , & AttractiveNode : : SetTeam } ,
{ & EV_AttractiveNode_SetUse , & AttractiveNode : : SetUse } ,
{ NULL , NULL }
} ;
Container < AttractiveNode * > attractiveNodes ;
AttractiveNode : : AttractiveNode ( )
{
m_iPriority = 0 ; // set to default 0
m_fMaxStayTime = 0 ; // set to default 0, could be just a pickup
m_fMaxDistance = 1024 ;
m_fMaxDistanceSquared = m_fMaxDistance * m_fMaxDistance ;
m_fRespawnTime = 15.0f ; // set to default 15 seconds
m_bUse = false ;
m_csTeam = STRING_NONE ;
m_iTeam = TEAM_NONE ;
attractiveNodes . AddObject ( this ) ;
}
AttractiveNode : : ~ AttractiveNode ( )
{
attractiveNodes . RemoveObject ( this ) ;
}
bool AttractiveNode : : CheckTeam
(
Sentient * sent
)
{
if ( ! m_iTeam )
{
return true ;
}
if ( sent - > IsSubclassOfPlayer ( ) )
{
Player * p = ( Player * ) sent ;
if ( ( m_iTeam = = TEAM_FREEFORALL & & g_gametype - > integer > = GT_TEAM ) | |
p - > GetTeam ( ) ! = m_iTeam )
{
return false ;
}
}
else
{
if ( m_iTeam = = TEAM_ALLIES & & sent - > m_Team ! = TEAM_AMERICAN )
{
return false ;
}
else if ( m_iTeam = = TEAM_AXIS & & sent - > m_Team ! = TEAM_GERMAN )
{
return false ;
}
}
return true ;
}
void AttractiveNode : : setMaxDist
(
float dist
)
{
m_fMaxDistance = dist ;
if ( dist < 0 )
{
m_fMaxDistanceSquared = - 1 ;
}
else
{
m_fMaxDistanceSquared = dist * dist ;
}
}
void AttractiveNode : : GetPriority
(
Event * ev
)
{
ev - > AddInteger ( m_iPriority ) ;
}
void AttractiveNode : : SetPriority
(
Event * ev
)
{
m_iPriority = ev - > GetInteger ( 1 ) ;
}
void AttractiveNode : : GetDistance
(
Event * ev
)
{
ev - > AddFloat ( m_fMaxDistance ) ;
}
void AttractiveNode : : SetDistance
(
Event * ev
)
{
setMaxDist ( ev - > GetFloat ( 1 ) ) ;
}
void AttractiveNode : : GetStayTime
(
Event * ev
)
{
ev - > AddFloat ( m_fMaxStayTime ) ;
}
void AttractiveNode : : SetStayTime
(
Event * ev
)
{
m_fMaxStayTime = ev - > GetFloat ( 1 ) ;
}
void AttractiveNode : : GetRespawnTime
(
Event * ev
)
{
ev - > AddFloat ( m_fRespawnTime ) ;
}
void AttractiveNode : : SetRespawnTime
(
Event * ev
)
{
m_fRespawnTime = ev - > GetFloat ( 1 ) ;
if ( m_fRespawnTime < 1.0f )
{
m_fRespawnTime = 1.0f ;
}
}
void AttractiveNode : : GetTeam
(
Event * ev
)
{
ev - > AddConstString ( m_csTeam ) ;
}
void AttractiveNode : : SetTeam
(
Event * ev
)
{
if ( ev - > IsNilAt ( 1 ) )
{
m_csTeam = STRING_NONE ;
m_iTeam = TEAM_NONE ;
return ;
}
m_csTeam = ev - > GetConstString ( 1 ) ;
switch ( m_csTeam )
{
case STRING_NONE :
m_iTeam = TEAM_NONE ;
break ;
case STRING_SPECTATOR :
m_iTeam = TEAM_SPECTATOR ;
break ;
case STRING_FREEFORALL :
m_iTeam = TEAM_FREEFORALL ;
break ;
case STRING_ALLIES :
case STRING_AMERICAN :
m_iTeam = TEAM_ALLIES ;
break ;
case STRING_AXIS :
case STRING_GERMAN :
m_iTeam = TEAM_AXIS ;
break ;
default :
m_iTeam = TEAM_NONE ;
ScriptError ( " Invalid team %s \n " , ev - > GetString ( 1 ) . c_str ( ) ) ;
}
}
void AttractiveNode : : SetUse
(
Event * ev
)
{
m_bUse = ev - > GetBoolean ( 1 ) ;
}