454 lines
7 KiB
C++
454 lines
7 KiB
C++
// Copyright (C) 1997 by Ritual Entertainment, Inc.
|
|
// All rights reserved.
|
|
//
|
|
// This source is may not be distributed and/or modified without
|
|
// expressly written permission by Ritual Entertainment, Inc.
|
|
//
|
|
// DESCRIPTION:
|
|
//
|
|
|
|
#include "g_local.h"
|
|
#include "entity.h"
|
|
#include "path.h"
|
|
#include "container.h"
|
|
#include "navigate.h"
|
|
#include "misc.h"
|
|
|
|
CLASS_DECLARATION( Class, Path, NULL );
|
|
|
|
ResponseDef Path::Responses[] =
|
|
{
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
Path::Path()
|
|
{
|
|
pathlength = 0;
|
|
from = NULL;
|
|
to = NULL;
|
|
nextnode = 1;
|
|
}
|
|
|
|
Path::Path
|
|
(
|
|
int numnodes
|
|
)
|
|
|
|
{
|
|
pathlength = 0;
|
|
from = NULL;
|
|
to = NULL;
|
|
nextnode = 1;
|
|
pathlist.Resize( numnodes );
|
|
dirToNextNode.Resize( numnodes );
|
|
distanceToNextNode.Resize( numnodes );
|
|
}
|
|
|
|
void Path::Clear
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
nextnode = 1;
|
|
pathlength = 0;
|
|
from = NULL;
|
|
to = NULL;
|
|
pathlist.FreeObjectList();
|
|
dirToNextNode.FreeObjectList();
|
|
distanceToNextNode.FreeObjectList();
|
|
}
|
|
|
|
void Path::Reset
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
nextnode = 1;
|
|
}
|
|
|
|
PathNode *Path::Start
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return from;
|
|
}
|
|
|
|
PathNode *Path::End
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return to;
|
|
}
|
|
|
|
void Path::AddNode
|
|
(
|
|
PathNode *node
|
|
)
|
|
|
|
{
|
|
Vector dir;
|
|
float len;
|
|
int num;
|
|
|
|
if ( !from )
|
|
{
|
|
from = node;
|
|
}
|
|
|
|
to = node;
|
|
pathlist.AddObject( PathNodePtr( node ) );
|
|
|
|
len = 0;
|
|
distanceToNextNode.AddObject( len );
|
|
dirToNextNode.AddObject( vec_zero );
|
|
|
|
num = NumNodes();
|
|
if ( num > 1 )
|
|
{
|
|
dir = node->worldorigin - GetNode( num - 1 )->worldorigin;
|
|
len = dir.length();
|
|
dir *= 1 / len;
|
|
|
|
distanceToNextNode.SetObjectAt( num - 1, len );
|
|
dirToNextNode.SetObjectAt( num - 1, dir );
|
|
|
|
pathlength += len;
|
|
}
|
|
}
|
|
|
|
PathNode *Path::GetNode
|
|
(
|
|
int num
|
|
)
|
|
|
|
{
|
|
PathNode *node;
|
|
|
|
node = pathlist.ObjectAt( num );
|
|
assert( node != NULL );
|
|
if ( node == NULL )
|
|
{
|
|
error( "GetNode", "Null pointer in node list\n" );
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
PathNode *Path::NextNode
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
if ( nextnode <= NumNodes() )
|
|
{
|
|
return pathlist.ObjectAt( nextnode++ );
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
PathNode *Path::NextNode
|
|
(
|
|
PathNode *node
|
|
)
|
|
|
|
{
|
|
int i;
|
|
int num;
|
|
PathNode *n;
|
|
|
|
num = NumNodes();
|
|
|
|
// NOTE: We specifically DON'T check the last object (hence the i < num instead
|
|
// of the usual i <= num, so don't go doing something stupid like trying to fix
|
|
// this without keeping this in mind!! :)
|
|
for( i = 1; i < num; i++ )
|
|
{
|
|
n = pathlist.ObjectAt( i );
|
|
if ( n == node )
|
|
{
|
|
// Since we only check up to num - 1, it's ok to do this.
|
|
// We do this since the last node in the list has no next node (duh!).
|
|
return pathlist.ObjectAt( i + 1 );
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
Vector Path::ClosestPointOnPath
|
|
(
|
|
Vector pos
|
|
)
|
|
|
|
{
|
|
PathNode *s;
|
|
PathNode *e;
|
|
int num;
|
|
int i;
|
|
float bestdist;
|
|
Vector bestpoint;
|
|
float dist;
|
|
float segmentlength;
|
|
Vector delta;
|
|
Vector p1;
|
|
Vector p2;
|
|
Vector p3;
|
|
float t;
|
|
|
|
num = NumNodes();
|
|
s = GetNode( 1 );
|
|
|
|
bestpoint = s->worldorigin;
|
|
delta = bestpoint - pos;
|
|
bestdist = delta * delta;
|
|
|
|
for( i = 2; i <= num; i++ )
|
|
{
|
|
e = GetNode( i );
|
|
|
|
// check if we're closest to the endpoint
|
|
delta = e->worldorigin - pos;
|
|
dist = delta * delta;
|
|
|
|
if ( dist < bestdist )
|
|
{
|
|
bestdist = dist;
|
|
bestpoint = e->worldorigin;
|
|
}
|
|
|
|
// check if we're closest to the segment
|
|
segmentlength = distanceToNextNode.ObjectAt( i - 1 );
|
|
p1 = dirToNextNode.ObjectAt( i - 1 );
|
|
p2 = pos - s->worldorigin;
|
|
|
|
t = p1 * p2;
|
|
if ( ( t > 0 ) && ( t < segmentlength ) )
|
|
{
|
|
p3 = ( p1 * t ) + s->worldorigin;
|
|
|
|
delta = p3 - pos;
|
|
dist = delta * delta;
|
|
if ( dist < bestdist )
|
|
{
|
|
bestdist = dist;
|
|
bestpoint = p3;
|
|
}
|
|
}
|
|
|
|
s = e;
|
|
}
|
|
|
|
return bestpoint;
|
|
}
|
|
|
|
float Path::DistanceAlongPath
|
|
(
|
|
Vector pos
|
|
)
|
|
|
|
{
|
|
PathNode *s;
|
|
PathNode *e;
|
|
int num;
|
|
int i;
|
|
float bestdist;
|
|
float dist;
|
|
float segmentlength;
|
|
Vector delta;
|
|
Vector p1;
|
|
Vector p2;
|
|
Vector p3;
|
|
float t;
|
|
float pathdist;
|
|
float bestdistalongpath;
|
|
|
|
pathdist = 0;
|
|
|
|
num = NumNodes();
|
|
s = GetNode( 1 );
|
|
delta = s->worldorigin - pos;
|
|
bestdist = delta * delta;
|
|
bestdistalongpath = 0;
|
|
|
|
for( i = 2; i <= num; i++ )
|
|
{
|
|
e = GetNode( i );
|
|
|
|
segmentlength = distanceToNextNode.ObjectAt( i - 1 );
|
|
|
|
// check if we're closest to the endpoint
|
|
delta = e->worldorigin - pos;
|
|
dist = delta * delta;
|
|
|
|
if ( dist < bestdist )
|
|
{
|
|
bestdist = dist;
|
|
bestdistalongpath = pathdist + segmentlength;
|
|
}
|
|
|
|
// check if we're closest to the segment
|
|
p1 = dirToNextNode.ObjectAt( i - 1 );
|
|
p2 = pos - s->worldorigin;
|
|
|
|
t = p1 * p2;
|
|
if ( ( t > 0 ) && ( t < segmentlength ) )
|
|
{
|
|
p3 = ( p1 * t ) + s->worldorigin;
|
|
|
|
delta = p3 - pos;
|
|
dist = delta * delta;
|
|
if ( dist < bestdist )
|
|
{
|
|
bestdist = dist;
|
|
bestdistalongpath = pathdist + t;
|
|
}
|
|
}
|
|
|
|
s = e;
|
|
|
|
pathdist += segmentlength;
|
|
}
|
|
|
|
return bestdistalongpath;
|
|
}
|
|
|
|
Vector Path::PointAtDistance
|
|
(
|
|
float dist
|
|
)
|
|
|
|
{
|
|
PathNode *s;
|
|
PathNode *e;
|
|
int num;
|
|
int i;
|
|
float t;
|
|
float pathdist;
|
|
float segmentlength;
|
|
|
|
num = NumNodes();
|
|
s = GetNode( 1 );
|
|
pathdist = 0;
|
|
|
|
for( i = 2; i <= num; i++ )
|
|
{
|
|
e = GetNode( i );
|
|
|
|
segmentlength = distanceToNextNode.ObjectAt( i - 1 );
|
|
if ( ( pathdist + segmentlength ) > dist )
|
|
{
|
|
t = dist - pathdist;
|
|
return s->worldorigin + dirToNextNode.ObjectAt( i - 1 ) * t;
|
|
}
|
|
|
|
s = e;
|
|
pathdist += segmentlength;
|
|
}
|
|
|
|
// cap it off at start or end of path
|
|
return s->worldorigin;
|
|
}
|
|
|
|
PathNode *Path::NextNode
|
|
(
|
|
float dist
|
|
)
|
|
|
|
{
|
|
PathNode *s;
|
|
PathNode *e;
|
|
int num;
|
|
int i;
|
|
float pathdist;
|
|
float segmentlength;
|
|
|
|
num = NumNodes();
|
|
s = GetNode( 1 );
|
|
pathdist = 0;
|
|
|
|
for( i = 2; i <= num; i++ )
|
|
{
|
|
e = GetNode( i );
|
|
|
|
segmentlength = distanceToNextNode.ObjectAt( i - 1 );
|
|
if ( ( pathdist + segmentlength ) > dist )
|
|
{
|
|
return e;
|
|
}
|
|
|
|
s = e;
|
|
pathdist += segmentlength;
|
|
}
|
|
|
|
// cap it off at start or end of path
|
|
return s;
|
|
}
|
|
|
|
void Path::DrawPath
|
|
(
|
|
float r,
|
|
float g,
|
|
float b,
|
|
float time
|
|
)
|
|
|
|
{
|
|
Vector s;
|
|
Vector e;
|
|
Vector offset;
|
|
PathNode *node;
|
|
int num;
|
|
int i;
|
|
|
|
num = NumNodes();
|
|
|
|
if ( ai_debugpath->value )
|
|
{
|
|
gi.dprintf( "numnodes %d, len %d, nodes %d :", PathManager.NumNodes(), ( int )Length(), num );
|
|
for( i = 1; i <= num; i++ )
|
|
{
|
|
node = GetNode( i );
|
|
gi.dprintf( " %d", node->nodenum );
|
|
}
|
|
|
|
gi.dprintf( "\n" );
|
|
}
|
|
|
|
node = GetNode( 1 );
|
|
s = node->worldorigin;
|
|
|
|
offset = Vector( r, g, b ) * 4 + Vector( 0, 0, 20 );
|
|
for( i = 2; i <= num; i++ )
|
|
{
|
|
node = GetNode( i );
|
|
e = node->worldorigin;
|
|
|
|
G_DebugLine( s + offset, e + offset, r, g, b, 1 );
|
|
s = e;
|
|
}
|
|
}
|
|
|
|
int Path::NumNodes
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return pathlist.NumObjects();
|
|
}
|
|
|
|
float Path::Length
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return pathlength;
|
|
}
|