mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 13:47:58 +03:00
658 lines
11 KiB
C++
658 lines
11 KiB
C++
/*
|
|
===========================================================================
|
|
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
|
|
===========================================================================
|
|
*/
|
|
|
|
// actor.cpp:
|
|
|
|
#include "actor.h"
|
|
|
|
ActorPath::ActorPath()
|
|
{
|
|
m_FallHeight = 96;
|
|
m_path = NULL;
|
|
m_pathlen = 0;
|
|
m_fLookAhead = 4096.0f;
|
|
m_bChangeLookAhead = true;
|
|
|
|
Clear();
|
|
}
|
|
|
|
ActorPath::~ActorPath()
|
|
{
|
|
if( m_path )
|
|
delete m_path;
|
|
}
|
|
|
|
void ActorPath::Clear
|
|
(
|
|
void
|
|
)
|
|
{
|
|
m_startpathpos = 0;
|
|
m_pathpos = 0;
|
|
m_Side = false;
|
|
m_Time = -10000000;
|
|
m_delta[ 0 ] = 0;
|
|
m_delta[ 1 ] = 0;
|
|
}
|
|
|
|
bool ActorPath::DoesTheoreticPathExist
|
|
(
|
|
float *start,
|
|
float *end,
|
|
class SimpleActor *ent,
|
|
float maxPath,
|
|
float *vLeashHome,
|
|
float fLeashDistSquared
|
|
)
|
|
{
|
|
return PathSearch::FindPath( start, end, ent, maxPath, NULL, 0, m_FallHeight ) != 0;
|
|
}
|
|
|
|
void ActorPath::FindPath
|
|
(
|
|
float *start,
|
|
float *end,
|
|
Entity *ent,
|
|
float maxPath,
|
|
float *vLeashHome,
|
|
float fLeashDistSquared
|
|
)
|
|
{
|
|
int depth = PathManager.FindPath( start, end, ent, maxPath, vLeashHome, fLeashDistSquared, m_FallHeight );
|
|
|
|
if( depth )
|
|
{
|
|
if( depth > m_pathlen )
|
|
{
|
|
if( m_path )
|
|
delete[] m_path;
|
|
|
|
m_pathlen = 10 * (( depth - 1 ) / 10) + 10;
|
|
m_path = new PathInfo[ m_pathlen ];
|
|
}
|
|
|
|
m_startpathpos = PathManager.GeneratePath( m_path );
|
|
m_pathpos = m_startpathpos;
|
|
m_TotalDist = PathManager.total_dist;
|
|
m_Side = false;
|
|
m_Time = level.inttime;
|
|
UpdatePos( start );
|
|
}
|
|
else
|
|
{
|
|
Clear();
|
|
}
|
|
}
|
|
|
|
void ActorPath::FindPathAway
|
|
(
|
|
float *start,
|
|
float *avoid,
|
|
float *vPreferredDir,
|
|
Entity *ent,
|
|
float fMinSafeDist,
|
|
float *vLeashHome,
|
|
float fLeashDistSquared
|
|
)
|
|
{
|
|
int depth = PathManager.FindPathAway( start, avoid, vPreferredDir, ent, fMinSafeDist, vLeashHome, fLeashDistSquared, m_FallHeight );
|
|
|
|
if( depth )
|
|
{
|
|
if( depth > m_pathlen )
|
|
{
|
|
if( m_path )
|
|
delete m_path;
|
|
|
|
m_pathlen = 10 * ( depth - 1 ) / 10 + 10;
|
|
m_path = new PathInfo[ m_pathlen ];
|
|
}
|
|
|
|
m_startpathpos = PathManager.GeneratePathAway( m_path );
|
|
m_pathpos = m_startpathpos;
|
|
m_TotalDist = PathManager.total_dist;
|
|
m_Side = false;
|
|
m_Time = level.inttime;
|
|
UpdatePos( start );
|
|
}
|
|
else
|
|
{
|
|
Clear();
|
|
}
|
|
}
|
|
|
|
void ActorPath::FindPathNear
|
|
(
|
|
float *start,
|
|
float *nearby,
|
|
Entity *ent,
|
|
float maxPath,
|
|
float fRadiusSquared,
|
|
float *vLeashHome,
|
|
float fLeashDistSquared
|
|
)
|
|
{
|
|
int depth = PathManager.FindPathNear( start, nearby, ent, maxPath, fRadiusSquared, vLeashHome, fLeashDistSquared, m_FallHeight );
|
|
|
|
if( depth )
|
|
{
|
|
if( depth > m_pathlen )
|
|
{
|
|
if( m_path )
|
|
delete m_path;
|
|
|
|
m_pathlen = 10 * ( depth - 1 ) / 10 + 10;
|
|
m_path = new PathInfo[ m_pathlen ];
|
|
}
|
|
|
|
m_startpathpos = PathManager.GeneratePathNear( m_path );
|
|
m_pathpos = m_startpathpos;
|
|
m_TotalDist = PathManager.total_dist;
|
|
m_Side = false;
|
|
m_Time = level.inttime;
|
|
UpdatePos( start );
|
|
}
|
|
else
|
|
{
|
|
Clear();
|
|
}
|
|
}
|
|
|
|
void ActorPath::ReFindPath
|
|
(
|
|
float *start,
|
|
Entity *ent
|
|
)
|
|
{
|
|
int depth = PathManager.FindPath( start, m_path->point, ent, 0, NULL, 0, m_FallHeight );
|
|
|
|
if( depth )
|
|
{
|
|
if( depth > m_pathlen )
|
|
{
|
|
if( m_path )
|
|
delete m_path;
|
|
|
|
m_pathlen = 10 * ( depth - 1 ) / 10 + 10;
|
|
m_path = new PathInfo[ m_pathlen ];
|
|
}
|
|
|
|
m_startpathpos = PathManager.GeneratePath( m_path );
|
|
m_pathpos = m_startpathpos;
|
|
m_TotalDist = PathManager.total_dist;
|
|
m_Side = false;
|
|
m_Time = level.inttime;
|
|
UpdatePos( start );
|
|
}
|
|
else
|
|
{
|
|
Clear();
|
|
}
|
|
}
|
|
|
|
float ActorPath::PathLookAhead
|
|
(
|
|
float total_area,
|
|
Vector& end,
|
|
float *origin
|
|
)
|
|
{
|
|
float area = total_area;
|
|
float s;
|
|
float t;
|
|
float normal[ 2 ];
|
|
float delta[ 2 ];
|
|
Vector pos;
|
|
float fallheight;
|
|
PathInfo *current_path = m_pathpos;
|
|
|
|
while( 1 )
|
|
{
|
|
pos = current_path->point;
|
|
|
|
if( current_path == m_path )
|
|
break;
|
|
|
|
fallheight = current_path->point[ 2 ] - origin[ 2 ];
|
|
|
|
if( fallheight > 94.0f || fallheight < -94.0f )
|
|
{
|
|
VectorCopy( current_path->point, end );
|
|
m_HasCompleteLookahead = false;
|
|
return area;
|
|
}
|
|
|
|
current_path--;
|
|
|
|
normal[ 0 ] = current_path->point[ 1 ] - pos[ 1 ];
|
|
normal[ 1 ] = pos[ 0 ] - current_path->point[ 0 ];
|
|
|
|
VectorNormalize2D( normal );
|
|
|
|
delta[ 0 ] = current_path->point[ 0 ] - origin[ 0 ];
|
|
delta[ 1 ] = current_path->point[ 1 ] - origin[ 1 ];
|
|
|
|
t = fabs( DotProduct2D( delta, normal ) ) * current_path->dist;
|
|
|
|
if( t >= area )
|
|
{
|
|
t = area / t;
|
|
s = 1.0f - t;
|
|
|
|
end[ 0 ] = current_path->point[ 0 ] * t + pos[ 0 ] * s;
|
|
end[ 1 ] = current_path->point[ 1 ] * t + pos[ 1 ] * s;
|
|
end[ 2 ] = current_path->point[ 2 ] * t + pos[ 2 ] * s;
|
|
m_HasCompleteLookahead = false;
|
|
return 0;
|
|
}
|
|
|
|
area -= t;
|
|
}
|
|
|
|
VectorCopy( current_path->point, end );
|
|
m_HasCompleteLookahead = true;
|
|
|
|
return area;
|
|
}
|
|
|
|
void ActorPath::UpdatePos
|
|
(
|
|
float *origin,
|
|
float fNodeRadius
|
|
)
|
|
{
|
|
Vector end;
|
|
float s = 0;
|
|
float t = 0;
|
|
vec2_t delta;
|
|
float current_dot = 0;
|
|
float previous_dot = 0;
|
|
Vector pos;
|
|
PathInfo *current_path = NULL;
|
|
vec2_t dir;
|
|
Vector end2;
|
|
vec2_t delta2;
|
|
vec2_t dir2;
|
|
|
|
if( m_pathpos == m_path )
|
|
{
|
|
end = m_pathpos->point;
|
|
m_bChangeLookAhead = true;
|
|
m_HasCompleteLookahead = true;
|
|
m_delta[ 0 ] = end[ 0 ] - origin[ 0 ];
|
|
m_delta[ 1 ] = end[ 1 ] - origin[ 1 ];
|
|
VectorNormalize2D2( m_delta, dir );
|
|
}
|
|
else if( m_fLookAhead >= 4096.0f )
|
|
{
|
|
if( m_fLookAhead - 4096.0f >= PathLookAhead( m_fLookAhead, end, origin ) )
|
|
{
|
|
Vector mins = Vector( -15, -15, 0 );
|
|
Vector maxs = Vector( 15, 15, 60 );
|
|
Vector e = end + Vector( 0, 0, 32 );
|
|
|
|
pos = origin + Vector( 0, 0, 32 );
|
|
|
|
if( G_SightTrace(
|
|
pos,
|
|
mins,
|
|
maxs,
|
|
e,
|
|
( gentity_t * )NULL, // g_entities[ 0 ].entity
|
|
0,
|
|
MASK_PLAYERSOLID,
|
|
false,
|
|
"Actor::UpdatePos 2" ) != true )
|
|
{
|
|
if( m_bChangeLookAhead )
|
|
{
|
|
m_fLookAhead -= 2048.0f;
|
|
m_bChangeLookAhead = false;
|
|
}
|
|
else
|
|
{
|
|
m_fLookAhead *= 0.5f;
|
|
}
|
|
|
|
if( m_fLookAhead < 4096.0f )
|
|
{
|
|
m_fLookAhead = 4096.0f;
|
|
}
|
|
|
|
PathLookAhead( 4096.0f, end, origin );
|
|
goto __setdelta;
|
|
}
|
|
}
|
|
|
|
m_fLookAhead += 1024.0f;
|
|
|
|
if( m_fLookAhead > 65536.0f )
|
|
m_fLookAhead = 65536.0f;
|
|
|
|
m_bChangeLookAhead = true;
|
|
|
|
__setdelta:
|
|
|
|
m_delta[ 0 ] = end[ 0 ] - origin[ 0 ];
|
|
m_delta[ 1 ] = end[ 1 ] - origin[ 1 ];
|
|
|
|
VectorNormalize2D2( m_delta, dir );
|
|
}
|
|
else if( PathLookAhead( 4096.0f, end, origin ) < 4096.0f - m_fLookAhead )
|
|
{
|
|
PathLookAhead( m_fLookAhead, end2, origin );
|
|
|
|
Vector mins = Vector( -15, -15, 0 );
|
|
Vector maxs = Vector( 15, 15, 60 );
|
|
Vector e = end2 + Vector( 0, 0, 32 );
|
|
|
|
pos = origin + Vector( 0, 0, 32 );
|
|
|
|
if( G_SightTrace(
|
|
pos,
|
|
mins,
|
|
maxs,
|
|
e,
|
|
( gentity_t * )NULL,
|
|
0,
|
|
MASK_MONSTERSOLID,
|
|
false,
|
|
"Actor::UpdatePos 1" ) != true )
|
|
{
|
|
m_fLookAhead += 1024.0f;
|
|
|
|
if( m_fLookAhead > 4096.0f )
|
|
m_fLookAhead = 4096.0f;
|
|
}
|
|
else
|
|
{
|
|
m_fLookAhead -= 1024.0f;
|
|
|
|
if( m_fLookAhead < 1024.0f )
|
|
m_fLookAhead = 1024.0f;
|
|
|
|
PathLookAhead( m_fLookAhead, end2, origin );
|
|
}
|
|
|
|
delta[ 0 ] = end2[ 0 ] - origin[ 0 ];
|
|
delta[ 1 ] = end2[ 1 ] - origin[ 1 ];
|
|
VectorNormalize2D2( delta, dir2 );
|
|
|
|
m_delta[ 0 ] = end[ 0 ] - origin[ 0 ];
|
|
m_delta[ 1 ] = end[ 1 ] - origin[ 1 ];
|
|
VectorNormalize2D2( m_delta, dir );
|
|
|
|
if( DotProduct2D( dir, dir2 ) > 0.7f )
|
|
{
|
|
m_delta[ 0 ] = delta[ 0 ];
|
|
m_delta[ 1 ] = delta[ 1 ];
|
|
}
|
|
|
|
m_bChangeLookAhead = true;
|
|
}
|
|
else
|
|
{
|
|
m_fLookAhead -= 1024.0f;
|
|
|
|
if( m_fLookAhead < 1024.0f )
|
|
m_fLookAhead = 1024.0f;
|
|
|
|
m_delta[ 0 ] = end[ 0 ] - origin[ 0 ];
|
|
m_delta[ 1 ] = end[ 1 ] - origin[ 1 ];
|
|
VectorNormalize2D2( m_delta, dir );
|
|
|
|
m_bChangeLookAhead = true;
|
|
}
|
|
|
|
current_path = m_pathpos;
|
|
|
|
while( 1 )
|
|
{
|
|
delta2[ 0 ] = current_path->point[ 0 ] - origin[ 0 ];
|
|
delta2[ 1 ] = current_path->point[ 1 ] - origin[ 1 ];
|
|
current_dot = DotProduct2D( delta2, dir ) - fNodeRadius;
|
|
|
|
if( current_dot >= 0.0f )
|
|
break;
|
|
|
|
previous_dot = current_dot;
|
|
|
|
if( current_path == LastNode() )
|
|
break;
|
|
|
|
current_path--;
|
|
}
|
|
|
|
if( current_path != m_pathpos )
|
|
{
|
|
m_pathpos = current_path + 1;
|
|
|
|
t = previous_dot / ( previous_dot - current_dot );
|
|
s = 1.0f - t;
|
|
|
|
/*m_pathpos->point[ 0 ] = m_pathpos->point[ 0 ] * s + current_path->point[ 0 ] * t;
|
|
m_pathpos->point[ 1 ] = m_pathpos->point[ 1 ] * s + current_path->point[ 1 ] * t;
|
|
m_pathpos->point[ 2 ] = m_pathpos->point[ 2 ] * s + current_path->point[ 2 ] * t;*/
|
|
|
|
VectorCopy( current_path->point, m_pathpos->point );
|
|
|
|
current_path->dist *= s;
|
|
|
|
m_Side = true;
|
|
}
|
|
else
|
|
{
|
|
m_Side = false;
|
|
}
|
|
}
|
|
|
|
bool ActorPath::Complete
|
|
(
|
|
const float *origin
|
|
) const
|
|
{
|
|
if( !m_HasCompleteLookahead )
|
|
return false;
|
|
|
|
if( !m_path )
|
|
return true;
|
|
|
|
if( fabs( origin[ 0 ] - m_path->point[ 0 ] ) < 16.0f &&
|
|
fabs( origin[ 1 ] - m_path->point[ 1 ] ) < 16.0f )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
PathInfo *ActorPath::StartNode
|
|
(
|
|
void
|
|
) const
|
|
{
|
|
return m_startpathpos;
|
|
}
|
|
|
|
PathInfo *ActorPath::CurrentNode
|
|
(
|
|
void
|
|
) const
|
|
{
|
|
return m_pathpos;
|
|
}
|
|
|
|
int ActorPath::CurrentNodeIndex
|
|
(
|
|
void
|
|
) const
|
|
{
|
|
return m_pathpos ? m_pathpos - m_path : -1;
|
|
}
|
|
|
|
PathInfo *ActorPath::NextNode
|
|
(
|
|
void
|
|
) const
|
|
{
|
|
return m_pathpos == m_path ? NULL : m_pathpos - 1;
|
|
}
|
|
|
|
PathInfo *ActorPath::LastNode
|
|
(
|
|
void
|
|
) const
|
|
{
|
|
return m_path;
|
|
}
|
|
|
|
Vector ActorPath::CurrentPathDir
|
|
(
|
|
void
|
|
) const
|
|
{
|
|
return Vector( m_pathpos->dir[ 0 ], m_pathpos->dir[ 1 ], 0 );
|
|
}
|
|
|
|
float *ActorPath::CurrentPathGoal
|
|
(
|
|
void
|
|
) const
|
|
{
|
|
return m_pathpos->point;
|
|
}
|
|
|
|
int ActorPath::Time
|
|
(
|
|
void
|
|
) const
|
|
{
|
|
return m_Time;
|
|
}
|
|
|
|
Vector ActorPath::CurrentDelta
|
|
(
|
|
void
|
|
) const
|
|
{
|
|
return Vector( m_delta[ 0 ], m_delta[ 1 ], 0 );
|
|
}
|
|
|
|
bool ActorPath::IsAccurate
|
|
(
|
|
void
|
|
) const
|
|
{
|
|
return m_pathpos->bAccurate;
|
|
}
|
|
|
|
float ActorPath::TotalDist
|
|
(
|
|
void
|
|
) const
|
|
{
|
|
return m_TotalDist;
|
|
}
|
|
|
|
void ActorPath::SetFallHeight
|
|
(
|
|
float fHeight
|
|
)
|
|
{
|
|
m_FallHeight = fHeight;
|
|
}
|
|
|
|
float ActorPath::GetFallHeight
|
|
(
|
|
void
|
|
) const
|
|
{
|
|
return m_FallHeight;
|
|
}
|
|
|
|
void ActorPath::TrimPathFromEnd
|
|
(
|
|
int nNodesPop
|
|
)
|
|
{
|
|
int iLastPos = m_path - m_pathpos;
|
|
|
|
if( iLastPos - nNodesPop > 0 )
|
|
{
|
|
for( int i = 0; i < iLastPos; i++ )
|
|
{
|
|
m_path[ i ] = m_path[ i + nNodesPop ];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Clear();
|
|
}
|
|
}
|
|
|
|
void ActorPath::Shorten
|
|
(
|
|
float fDistRemove
|
|
)
|
|
{
|
|
if( m_path->dist > fDistRemove )
|
|
{
|
|
m_path->point[ 0 ] += m_path->dir[ 0 ] * -fDistRemove;
|
|
m_path->point[ 1 ] += m_path->dir[ 1 ] * -fDistRemove;
|
|
m_path->point[ 2 ] += m_path->point[ 2 ] * -fDistRemove;
|
|
m_path->dist -= fDistRemove;
|
|
}
|
|
else
|
|
{
|
|
while( fDistRemove - m_path->dist > m_path->dist )
|
|
{
|
|
TrimPathFromEnd( 1 );
|
|
|
|
if( !m_pathpos )
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ActorPath::HasCompleteLookahead
|
|
(
|
|
void
|
|
) const
|
|
{
|
|
return m_HasCompleteLookahead;
|
|
}
|
|
|
|
bool ActorPath::IsSide
|
|
(
|
|
void
|
|
) const
|
|
{
|
|
return m_Side;
|
|
}
|
|
|
|
void ActorPath::ForceShortLookahead
|
|
(
|
|
void
|
|
)
|
|
{
|
|
m_fLookAhead = 4096.0f;
|
|
}
|