openmohaa/code/fgame/actorpath.cpp

552 lines
13 KiB
C++
Raw Normal View History

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
===========================================================================
*/
// actor.cpp:
#include "actor.h"
ActorPath::ActorPath()
{
2023-10-12 20:18:22 +02:00
m_FallHeight = 96;
m_path = NULL;
m_pathlen = 0;
2023-10-15 17:52:00 +02:00
m_fLookAhead = 4096;
2023-10-12 20:18:22 +02:00
m_bChangeLookAhead = true;
2016-03-27 11:49:47 +02:00
2023-10-12 20:18:22 +02:00
Clear();
2016-03-27 11:49:47 +02:00
}
ActorPath::~ActorPath()
{
2023-10-12 20:18:22 +02:00
if (m_path) {
delete[] m_path;
}
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
void ActorPath::Clear(void)
2016-03-27 11:49:47 +02:00
{
2023-10-15 17:52:00 +02:00
m_startpathpos = NULL;
m_pathpos = NULL;
2023-10-12 20:18:22 +02:00
m_Side = false;
m_Time = -10000000;
2023-10-15 17:52:00 +02:00
VectorClear2D(m_delta);
m_TotalDist = PathManager.total_dist;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:30:27 +02:00
void ActorPath::ForceShortLookahead(void)
{
m_fLookAhead = 4096.0f;
}
float ActorPath::PathLookAhead(float total_area, Vector& end, float *origin)
{
float area = total_area;
float s;
float t;
2023-10-15 17:52:00 +02:00
vec2_t normal;
vec2_t delta;
2023-10-12 20:30:27 +02:00
Vector pos;
float fallheight;
PathInfo *current_path = m_pathpos;
2023-10-15 17:52:00 +02:00
pos = current_path->point;
2023-10-12 20:30:27 +02:00
2023-10-15 17:52:00 +02:00
while (1) {
2023-10-12 20:30:27 +02:00
if (current_path == m_path) {
2023-10-15 17:52:00 +02:00
end = current_path->point;
m_HasCompleteLookahead = true;
return area;
2023-10-12 20:30:27 +02:00
}
fallheight = current_path->point[2] - origin[2];
if (fallheight > 94.0f || fallheight < -94.0f) {
2023-10-15 17:52:00 +02:00
end = current_path->point;
2023-10-12 20:30:27 +02:00
m_HasCompleteLookahead = false;
return area;
}
current_path--;
2023-10-15 17:52:00 +02:00
// calculate the normal
2023-10-12 20:30:27 +02:00
normal[0] = current_path->point[1] - pos[1];
normal[1] = pos[0] - current_path->point[0];
VectorNormalize2D(normal);
2023-10-15 17:52:00 +02:00
VectorSub2D(current_path->point, origin, delta);
2023-10-12 20:30:27 +02:00
t = fabs(DotProduct2D(delta, normal)) * current_path->dist;
if (t >= area) {
2023-10-15 17:52:00 +02:00
break;
2023-10-12 20:30:27 +02:00
}
area -= t;
2023-10-15 17:52:00 +02:00
pos = current_path->point;
2023-10-12 20:30:27 +02:00
}
2023-10-15 17:52:00 +02:00
t = area / t;
s = 1.0f - t;
2023-10-23 12:39:09 +02:00
end[0] = pos[0] * s + current_path->point[0] * t;
end[1] = pos[1] * s + current_path->point[1] * t;
end[2] = pos[2] * s + current_path->point[2] * t;
2023-10-12 20:30:27 +02:00
2023-10-15 17:52:00 +02:00
m_HasCompleteLookahead = false;
return 0;
2023-10-12 20:30:27 +02:00
}
2023-10-12 20:18:22 +02:00
bool ActorPath::DoesTheoreticPathExist(
float *start, float *end, class SimpleActor *ent, float maxPath, float *vLeashHome, float fLeashDistSquared
)
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
return PathSearch::FindPath(start, end, ent, maxPath, NULL, 0, m_FallHeight) != 0;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
void ActorPath::FindPath(
float *start, float *end, Entity *ent, float maxPath, float *vLeashHome, float fLeashDistSquared
)
2016-03-27 11:49:47 +02:00
{
2023-10-15 17:52:00 +02:00
int depth;
2023-10-12 20:18:22 +02:00
2023-10-15 17:52:00 +02:00
depth = PathManager.FindPath(start, end, ent, maxPath, vLeashHome, fLeashDistSquared, m_FallHeight);
2023-10-12 20:18:22 +02:00
2023-10-15 17:52:00 +02:00
if (!depth) {
Clear();
return;
}
if (depth > m_pathlen) {
if (m_path) {
delete[] m_path;
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:52:00 +02:00
m_pathlen = 10 * ((depth - 1) / 10) + 10;
m_path = new PathInfo[m_pathlen];
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:52:00 +02:00
m_startpathpos = PathManager.GeneratePath(m_path);
m_pathpos = m_startpathpos;
m_TotalDist = PathManager.total_dist;
m_Side = false;
m_Time = level.inttime;
UpdatePos(start);
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
void ActorPath::FindPathAway(
float *start,
float *avoid,
float *vPreferredDir,
Entity *ent,
float fMinSafeDist,
float *vLeashHome,
float fLeashDistSquared
)
2016-03-27 11:49:47 +02:00
{
2023-10-15 17:52:00 +02:00
int depth;
depth = PathManager.FindPathAway(
2023-10-12 20:18:22 +02:00
start, avoid, vPreferredDir, ent, fMinSafeDist, vLeashHome, fLeashDistSquared, m_FallHeight
);
2023-10-15 17:52:00 +02:00
if (!depth) {
Clear();
return;
}
2023-10-12 20:18:22 +02:00
2023-10-15 17:52:00 +02:00
if (depth > m_pathlen) {
if (m_path) {
delete[] m_path;
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:52:00 +02:00
m_pathlen = 10 * (depth - 1) / 10 + 10;
m_path = new PathInfo[m_pathlen];
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:52:00 +02:00
m_startpathpos = PathManager.GeneratePathAway(m_path);
m_pathpos = m_startpathpos;
m_TotalDist = PathManager.total_dist;
m_Side = false;
m_Time = level.inttime;
UpdatePos(start);
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
void ActorPath::FindPathNear(
float *start,
float *nearby,
Entity *ent,
float maxPath,
float fRadiusSquared,
float *vLeashHome,
float fLeashDistSquared
)
2016-03-27 11:49:47 +02:00
{
2023-10-15 17:52:00 +02:00
int depth;
depth = PathManager.FindPathNear(
2023-10-12 20:18:22 +02:00
start, nearby, ent, maxPath, fRadiusSquared, vLeashHome, fLeashDistSquared, m_FallHeight
);
2023-10-15 17:52:00 +02:00
if (!depth) {
Clear();
return;
}
2023-10-12 20:18:22 +02:00
2023-10-15 17:52:00 +02:00
if (depth > m_pathlen) {
if (m_path) {
delete[] m_path;
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:52:00 +02:00
m_pathlen = 10 * (depth - 1) / 10 + 10;
m_path = new PathInfo[m_pathlen];
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:52:00 +02:00
m_startpathpos = PathManager.GeneratePathNear(m_path);
m_pathpos = m_startpathpos;
m_TotalDist = PathManager.total_dist;
m_Side = false;
m_Time = level.inttime;
UpdatePos(start);
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
void ActorPath::ReFindPath(float *start, Entity *ent)
2016-03-27 11:49:47 +02:00
{
2023-10-15 17:52:00 +02:00
int depth;
2023-10-12 20:18:22 +02:00
vec3_t point;
// this is a critical bug in all versions of mohaa, it passes directly m_path->point
// but m_path can be deleted afterwards, leaving a dangling pointer to the path_end
// global variable
VectorCopy(m_path->point, point);
2023-10-15 17:52:00 +02:00
depth = PathManager.FindPath(start, point, ent, 0, NULL, 0, m_FallHeight);
2023-10-12 20:18:22 +02:00
2023-10-15 17:52:00 +02:00
if (!depth) {
Clear();
return;
}
if (depth > m_pathlen) {
if (m_path) {
delete[] m_path;
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:52:00 +02:00
m_pathlen = 10 * (depth - 1) / 10 + 10;
m_path = new PathInfo[m_pathlen];
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:52:00 +02:00
m_startpathpos = PathManager.GeneratePath(m_path);
m_pathpos = m_startpathpos;
m_TotalDist = PathManager.total_dist;
m_Side = false;
m_Time = level.inttime;
UpdatePos(start);
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
void ActorPath::UpdatePos(float *origin, float fNodeRadius)
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
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;
2023-10-15 17:52:00 +02:00
VectorSub2D(end, origin, m_delta);
2023-10-12 20:18:22 +02:00
VectorNormalize2D2(m_delta, dir);
} else if (m_fLookAhead >= 4096.0f) {
2023-11-02 19:33:10 +01:00
if (PathLookAhead(m_fLookAhead, end, origin) > (m_fLookAhead - 4096.0f)
2023-10-23 12:39:09 +02:00
|| G_SightTrace(
2023-10-15 17:52:00 +02:00
origin + Vector(0, 0, 32),
Vector(-15, -15, 0),
Vector(15, 15, 60),
end + Vector(0, 0, 32),
2023-10-23 12:39:09 +02:00
g_entities[0].entity,
NULL,
MASK_ACTORPATH,
2023-10-15 17:52:00 +02:00
false,
"Actor::UpdatePos 2"
)) {
m_fLookAhead += 1024.0f;
2023-10-12 20:18:22 +02:00
2023-10-23 12:39:09 +02:00
if (m_fLookAhead > Square(256)) {
m_fLookAhead = Square(256);
2023-10-15 17:52:00 +02:00
}
2023-10-12 20:18:22 +02:00
2023-10-15 17:52:00 +02:00
m_bChangeLookAhead = true;
} else {
if (m_bChangeLookAhead) {
m_fLookAhead -= 2048.0f;
m_bChangeLookAhead = false;
} else {
m_fLookAhead /= 2.f;
}
2023-10-12 20:18:22 +02:00
2023-10-15 17:52:00 +02:00
if (m_fLookAhead < 4096.0f) {
m_fLookAhead = 4096.0f;
}
2023-10-12 20:18:22 +02:00
2023-10-23 12:39:09 +02:00
PathLookAhead(m_fLookAhead, end, origin);
2023-10-15 17:52:00 +02:00
}
2023-10-12 20:18:22 +02:00
2023-10-15 17:52:00 +02:00
VectorSub2D(end, origin, m_delta);
2023-10-12 20:18:22 +02:00
VectorNormalize2D2(m_delta, dir);
} else if (PathLookAhead(4096.0f, end, origin) < 4096.0f - m_fLookAhead) {
PathLookAhead(m_fLookAhead, end2, origin);
2023-10-15 17:52:00 +02:00
if (!G_SightTrace(
2023-10-23 12:39:09 +02:00
origin + Vector(0, 0, 32),
2023-10-15 17:52:00 +02:00
Vector(-15, -15, 0),
Vector(15, 15, 60),
end2 + Vector(0, 0, 32),
2023-10-23 12:39:09 +02:00
g_entities[0].entity,
2023-10-15 17:52:00 +02:00
0,
2023-10-23 12:39:09 +02:00
MASK_ACTORPATH,
2023-10-15 17:52:00 +02:00
false,
"Actor::UpdatePos 1"
)) {
2023-10-12 20:18:22 +02:00
m_fLookAhead -= 1024.0f;
if (m_fLookAhead < 1024.0f) {
m_fLookAhead = 1024.0f;
}
PathLookAhead(m_fLookAhead, end2, origin);
2023-10-15 17:52:00 +02:00
} else {
m_fLookAhead += 1024.0f;
if (m_fLookAhead > 4096.0f) {
m_fLookAhead = 4096.0f;
}
2023-10-12 20:18:22 +02:00
}
2023-10-15 17:52:00 +02:00
VectorSub2D(end2, origin, delta);
2023-10-12 20:18:22 +02:00
VectorNormalize2D2(delta, dir2);
2023-10-15 17:52:00 +02:00
VectorSub2D(end, origin, delta);
2023-10-12 20:18:22 +02:00
VectorNormalize2D2(m_delta, dir);
if (DotProduct2D(dir, dir2) > 0.7f) {
2023-10-23 12:39:09 +02:00
VectorCopy2D(delta, m_delta);
2023-10-15 17:52:00 +02:00
VectorCopy2D(dir2, dir);
2023-10-12 20:18:22 +02:00
}
2023-10-23 12:39:09 +02:00
m_bChangeLookAhead = true;
2023-10-12 20:18:22 +02:00
} else {
m_fLookAhead -= 1024.0f;
if (m_fLookAhead < 1024.0f) {
m_fLookAhead = 1024.0f;
}
2023-10-15 17:52:00 +02:00
VectorSub2D(end, origin, m_delta);
2023-10-12 20:18:22 +02:00
VectorNormalize2D2(m_delta, dir);
2023-10-15 17:52:00 +02:00
2023-10-23 12:39:09 +02:00
m_bChangeLookAhead = true;
}
2016-03-27 11:49:47 +02:00
2023-10-23 12:39:09 +02:00
// Check added in OPM.
// Make sure to stop if it's the last node
for (current_path = m_pathpos; current_path >= LastNode(); current_path--) {
2023-10-15 17:52:00 +02:00
VectorSub2D(current_path->point, origin, delta2);
//current_dot = DotProduct2D(delta2, dir) - fNodeRadius;
// Removed in 2.0
// fNodeRadius is now unused?
current_dot = DotProduct2D(delta2, dir);
2016-03-27 11:49:47 +02:00
2023-10-15 17:52:00 +02:00
if (current_dot >= 0) {
2023-10-12 20:18:22 +02:00
break;
}
2016-03-27 11:49:47 +02:00
2023-10-12 20:18:22 +02:00
previous_dot = current_dot;
}
if (current_path != m_pathpos) {
m_pathpos = current_path + 1;
t = previous_dot / (previous_dot - current_dot);
s = 1.0f - t;
2023-10-15 17:52:00 +02:00
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;
2023-10-12 20:18:22 +02:00
current_path->dist *= s;
2016-03-27 11:49:47 +02:00
2023-10-12 20:18:22 +02:00
m_Side = true;
} else {
m_Side = false;
}
2023-10-15 17:52:00 +02:00
// Added in 2.0.
// Make sure to clear the delta if it's invalid (NaN, infinite...)
if (!isfinite(m_delta[0]) || !isfinite(m_delta[1])) {
VectorClear2D(m_delta);
}
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
bool ActorPath::Complete(const float *origin) const
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
if (!m_HasCompleteLookahead) {
return false;
}
2016-03-27 11:49:47 +02:00
2023-10-12 20:18:22 +02:00
if (fabs(origin[0] - m_path->point[0]) < 16.0f && fabs(origin[1] - m_path->point[1]) < 16.0f) {
return true;
}
2016-03-27 11:49:47 +02:00
2023-10-12 20:18:22 +02:00
return false;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:30:27 +02:00
void ActorPath::TrimPathFromEnd(int nNodesPop)
{
2023-10-15 17:52:00 +02:00
int iLastPos;
2023-10-12 20:30:27 +02:00
2023-10-15 17:52:00 +02:00
iLastPos = m_path - m_pathpos;
if (iLastPos < 0) {
2023-10-12 20:30:27 +02:00
Clear();
2023-10-15 17:52:00 +02:00
return;
}
m_pathpos -= nNodesPop;
for (int i = 0; i < iLastPos; i++) {
m_path[i] = m_path[i + nNodesPop];
2023-10-12 20:30:27 +02:00
}
}
void ActorPath::Shorten(float fDistRemove)
{
2023-10-15 17:52:00 +02:00
while (m_path->dist >= fDistRemove) {
fDistRemove -= m_path->dist;
TrimPathFromEnd(1);
if (!m_pathpos) {
return;
2023-10-12 20:30:27 +02:00
}
}
2023-10-15 17:52:00 +02:00
m_path->point[0] += m_path->dir[0] * -fDistRemove;
m_path->point[1] += m_path->dir[1] * -fDistRemove;
// Fixed in OPM.
// This is a bug in mohaa as it can write past the end of the class instance
//m_path->point[2] += m_path->dir[2] * -fDistRemove;
m_path->dist -= fDistRemove;
2023-10-12 20:30:27 +02:00
}
2023-10-12 20:18:22 +02:00
PathInfo *ActorPath::StartNode(void) const
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
return m_startpathpos;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
PathInfo *ActorPath::CurrentNode(void) const
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
return m_pathpos;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
int ActorPath::CurrentNodeIndex(void) const
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
return m_pathpos ? m_pathpos - m_path : -1;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
PathInfo *ActorPath::NextNode(void) const
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
return m_pathpos == m_path ? NULL : m_pathpos - 1;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
PathInfo *ActorPath::LastNode(void) const
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
return m_path;
2016-03-27 11:49:47 +02:00
}
const float *ActorPath::CurrentPathDir(void) const
2016-03-27 11:49:47 +02:00
{
if (m_pathpos == m_path) {
return m_delta;
} else {
return m_pathpos[-1].dir;
}
2016-03-27 11:49:47 +02:00
}
const float *ActorPath::CurrentPathGoal(void) const
2016-03-27 11:49:47 +02:00
{
2023-10-15 17:52:00 +02:00
return m_path->point;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
int ActorPath::Time(void) const
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
return m_Time;
2016-03-27 11:49:47 +02:00
}
2023-10-15 17:52:00 +02:00
const float *ActorPath::CurrentDelta(void) const
2016-03-27 11:49:47 +02:00
{
2023-10-15 17:52:00 +02:00
return m_delta;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
bool ActorPath::IsAccurate(void) const
2016-03-27 11:49:47 +02:00
{
2023-10-15 17:52:00 +02:00
if (m_pathpos == m_path) {
return false;
}
if (!m_pathpos[-1].bAccurate) {
return false;
}
if (!m_Side) {
return false;
}
return true;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
void ActorPath::SetFallHeight(float fHeight)
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
m_FallHeight = fHeight;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
float ActorPath::GetFallHeight(void) const
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
return m_FallHeight;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:18:22 +02:00
bool ActorPath::HasCompleteLookahead(void) const
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:18:22 +02:00
return m_HasCompleteLookahead;
2016-03-27 11:49:47 +02:00
}
2023-10-12 20:30:27 +02:00
float ActorPath::TotalDist(void) const
2018-08-19 08:26:59 +02:00
{
2023-10-12 20:30:27 +02:00
return m_TotalDist;
2018-08-19 08:26:59 +02:00
}
2023-10-12 20:30:27 +02:00
bool ActorPath::IsSide(void) const
2016-03-27 11:49:47 +02:00
{
2023-10-12 20:30:27 +02:00
return m_Side;
2016-03-27 11:49:47 +02:00
}