openmohaa/code/fgame/navigate.h

392 lines
12 KiB
C
Raw Normal View History

2016-03-27 11:49:47 +02:00
/*
===========================================================================
2023-10-22 21:06:43 +02:00
Copyright (C) 2023 the OpenMoHAA team
2016-03-27 11:49:47 +02:00
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.h:
// Potentially could be an C++ implementation of the A* search algorithm, but
// is currently unfinished.
//
2023-10-22 21:06:43 +02:00
#pragma once
2016-03-27 11:49:47 +02:00
#include "g_local.h"
#include "class.h"
#include "entity.h"
#include "stack.h"
#include "container.h"
#include "doors.h"
2023-01-29 20:59:31 +01:00
#include "sentient.h"
2016-03-27 11:49:47 +02:00
#include "../qcommon/qfiles.h"
extern Event EV_AI_SavePaths;
extern Event EV_AI_SaveNodes;
extern Event EV_AI_LoadNodes;
extern Event EV_AI_ClearNodes;
extern Event EV_AI_RecalcPaths;
extern Event EV_AI_CalcPath;
extern Event EV_AI_DisconnectPath;
2023-10-22 21:06:43 +02:00
extern cvar_t *ai_showroutes;
extern cvar_t *ai_showroutes_distance;
extern cvar_t *ai_shownodenums;
extern cvar_t *ai_shownode;
extern cvar_t *ai_showallnode;
extern cvar_t *ai_showpath;
extern cvar_t *ai_fallheight;
extern cvar_t *ai_debugpath;
extern cvar_t *ai_pathchecktime;
extern cvar_t *ai_pathcheckdist;
2016-03-27 11:49:47 +02:00
2023-10-22 21:06:43 +02:00
extern int ai_maxnode;
2016-03-27 11:49:47 +02:00
#define MAX_PATHCHECKSPERFRAME 4
extern int path_checksthisframe;
2023-10-22 21:06:43 +02:00
#define MAX_PATH_LENGTH 128 // should be more than plenty
#define NUM_PATHSPERNODE 48
2016-03-27 11:49:47 +02:00
class Path;
class PathNode;
2023-10-22 21:06:43 +02:00
#define NUM_WIDTH_VALUES 16
#define WIDTH_STEP 8
#define MAX_WIDTH (WIDTH_STEP * NUM_WIDTH_VALUES)
#define MAX_HEIGHT 128
2016-03-27 11:49:47 +02:00
2023-10-22 21:06:43 +02:00
#define CHECK_PATH(path, width, height) \
((((width) >= MAX_WIDTH) || ((width) < 0)) ? false \
: ((int)(path)->maxheight[((width) / WIDTH_STEP) - 1] < (int)(height)))
2016-03-27 11:49:47 +02:00
2023-10-22 21:06:43 +02:00
class pathway_ref
{
2016-03-27 11:49:47 +02:00
public:
2023-10-22 21:06:43 +02:00
short int from;
short int to;
2016-03-27 11:49:47 +02:00
};
typedef struct {
2023-10-22 21:06:43 +02:00
byte numBlockers;
2023-10-24 19:30:13 +02:00
byte badPlaceTeam[2];
2023-10-22 21:06:43 +02:00
short int node;
short int fallheight;
float dist;
float dir[2];
float pos1[3];
float pos2[3];
2016-03-27 11:49:47 +02:00
} pathway_t;
2023-10-22 21:06:43 +02:00
class PathInfo
{
2016-03-27 11:49:47 +02:00
public:
2023-10-22 21:06:43 +02:00
bool bAccurate;
float point[3];
float dist;
float dir[2];
2016-03-27 11:49:47 +02:00
public:
2023-10-22 21:06:43 +02:00
void Archive(Archiver& arc);
2016-03-27 11:49:47 +02:00
};
2023-10-22 21:06:43 +02:00
inline void PathInfo::Archive(Archiver& arc)
2016-03-27 11:49:47 +02:00
{
2023-10-22 21:06:43 +02:00
arc.ArchiveBool(&bAccurate);
arc.ArchiveVec3(point);
arc.ArchiveFloat(&dist);
arc.ArchiveVec2(dir);
2016-03-27 11:49:47 +02:00
}
2023-10-22 21:06:43 +02:00
typedef enum {
NOT_IN_LIST,
IN_OPEN,
IN_CLOSED
} pathlist_t;
#define PATH_DONT_LINK 1
#define AI_DUCK 2
#define AI_COVER 4
#define AI_CONCEALMENT 8
#define AI_CORNER_LEFT 16
#define AI_CORNER_RIGHT 32
#define AI_SNIPER 64
#define AI_CRATE 128
#define AI_COVERFLAGS (AI_CRATE | AI_SNIPER | AI_CORNER_RIGHT | AI_CORNER_LEFT | AI_CONCEALMENT | AI_COVER)
#define AI_COVERFLAGS2 (AI_SNIPER | AI_CORNER_RIGHT | AI_CORNER_LEFT | AI_CONCEALMENT)
#define AI_COVERFLAGS3 (AI_SNIPER | AI_CORNER_RIGHT | AI_CORNER_LEFT | AI_CONCEALMENT | AI_DUCK | AI_CONCEALMENT)
#define AI_SNIPERFLAGS (AI_SNIPER | AI_CORNER_RIGHT | AI_CORNER_LEFT | AI_COVER)
#define AI_CRATEFLAGS (AI_CRATE | AI_CORNER_LEFT | AI_CORNER_RIGHT | AI_CONCEALMENT | AI_COVER | AI_DUCK)
#define AI_COVER_LEFT_FLAGS (AI_CRATE | AI_SNIPER | AI_CORNER_LEFT | AI_CONCEALMENT | AI_DUCK)
#define AI_COVER_RIGHT_FLAGS (AI_CRATE | AI_SNIPER | AI_CORNER_RIGHT | AI_CONCEALMENT | AI_DUCK)
2023-10-29 20:20:12 +01:00
#define AI_COVER_MASK (AI_CRATE | AI_CORNER_RIGHT | AI_CORNER_LEFT | AI_CONCEALMENT | AI_COVER)
2023-10-22 21:06:43 +02:00
#define AI_ALL (AI_DUCK | AI_COVER | AI_CONCEALMENT | AI_CORNER_LEFT | AI_CORNER_RIGHT | AI_SNIPER | AI_CRATE)
void DrawNode(int iNodeCount);
void DrawAllConnections(void);
2016-03-27 11:49:47 +02:00
class PathNode : public SimpleEntity
2023-10-22 21:06:43 +02:00
{
public:
int findCount;
pathway_t *Child;
int numChildren;
int virtualNumChildren;
float f;
float h;
float g;
class PathNode *Parent;
bool inopen;
PathNode *PrevNode;
PathNode *NextNode;
short int pathway;
vec_t *m_PathPos;
float dist;
float dir[2];
int nodeflags;
SafePtr<Entity> pLastClaimer;
int iAvailableTime;
int nodenum;
short int m_Depth;
friend class PathSearch;
friend void DrawAllConnections(void);
private:
void ConnectTo(PathNode *node);
void SetNodeFlags(Event *ev);
void Remove(Event *ev);
public:
CLASS_PROTOTYPE(PathNode);
void *operator new(size_t size);
void operator delete(void *ptr);
PathNode();
virtual ~PathNode();
void Archive(Archiver& arc) override;
void ArchiveDynamic(Archiver& arc);
void ArchiveStatic(Archiver& arc);
bool CheckPathTo(PathNode *node);
void CheckPathToDefault(PathNode *node, pathway_t *pathway);
qboolean LadderTo(PathNode *node, pathway_t *pathway);
void DrawConnections(void);
void Claim(Entity *pClaimer);
void Relinquish(void);
Entity *GetClaimHolder(void) const;
bool IsClaimedByOther(Entity *pPossibleClaimer) const;
void MarkTemporarilyBad(void);
void ConnectChild(int i);
void DisconnectChild(int i);
const_str GetSpecialAttack(class Actor *pActor);
void IsTouching(Event *ev);
qboolean IsTouching(Entity *e1);
void setOriginEvent(Vector org) override;
};
2016-03-27 11:49:47 +02:00
typedef SafePtr<PathNode> PathNodePtr;
2023-10-22 21:06:43 +02:00
class nodeinfo
{
2018-09-17 23:50:38 +02:00
public:
2023-10-22 21:06:43 +02:00
PathNode *pNode;
float fDistSquared;
2018-09-17 23:50:38 +02:00
};
2023-10-22 21:06:43 +02:00
#define PATHMAP_CELLSIZE 256
#define PATHMAP_GRIDSIZE (MAX_MAP_BOUNDS * 2 / PATHMAP_CELLSIZE)
2016-03-27 11:49:47 +02:00
2023-10-22 21:06:43 +02:00
#define PATHMAP_NODES 128 // 128 - sizeof( int ) / sizeof( short )
2016-03-27 11:49:47 +02:00
2023-10-22 21:06:43 +02:00
#define MAX_PATHNODES 4096
2016-03-27 11:49:47 +02:00
class MapCell : public Class
{
private:
2023-10-22 21:06:43 +02:00
int numnodes;
short *nodes;
2016-03-27 11:49:47 +02:00
2023-10-22 21:06:43 +02:00
friend class PathSearch;
2016-03-27 11:49:47 +02:00
public:
2023-10-22 21:06:43 +02:00
MapCell();
~MapCell();
2016-03-27 11:49:47 +02:00
2023-10-22 21:06:43 +02:00
qboolean AddNode(PathNode *node);
int NumNodes(void);
2016-03-27 11:49:47 +02:00
};
class PathSearch : public Listener
{
2023-10-22 21:06:43 +02:00
friend class PathNode;
2016-03-27 11:49:47 +02:00
private:
2023-10-22 21:06:43 +02:00
static MapCell PathMap[PATHMAP_GRIDSIZE][PATHMAP_GRIDSIZE];
static PathNode *open;
static int findFrame;
static qboolean m_bNodesloaded;
static qboolean m_NodeCheckFailed;
static int m_LoadIndex;
2016-03-27 11:49:47 +02:00
public:
2023-10-22 21:06:43 +02:00
static PathNode *pathnodes[4096];
static int nodecount;
static float total_dist;
static const char *last_error;
2016-03-27 11:49:47 +02:00
private:
2023-10-22 21:06:43 +02:00
static void LoadAddToGrid(int x, int y);
static void LoadAddToGrid2(PathNode *node, int x, int y);
static void AddToGrid(PathNode *node, int x, int y);
static bool Connect(PathNode *node, int x, int y);
static int NodeCoordinate(float coord);
static int GridCoordinate(float coord);
static qboolean ArchiveSaveNodes(void);
static void ArchiveLoadNodes(void);
static void Init(void);
2016-03-27 11:49:47 +02:00
public:
2023-10-22 21:06:43 +02:00
CLASS_PROTOTYPE(PathSearch);
PathSearch();
virtual ~PathSearch();
static void ArchiveStaticLoad(Archiver &arc);
static void ArchiveStaticSave(Archiver &arc);
static bool ArchiveDynamic(Archiver &arc);
static void AddNode(PathNode *node);
static void Connect(PathNode *node);
static void UpdateNode(PathNode *node);
static MapCell *GetNodesInCell(int x, int y);
static MapCell *GetNodesInCell(float *pos);
static class PathNode *DebugNearestStartNode(float *pos, Entity *ent = NULL);
static class PathNode *NearestStartNode(float *pos, class SimpleActor *ent);
static class PathNode *NearestEndNode(float *pos);
static int DebugNearestNodeList(float *pos, PathNode **nodelist, int iMaxNodes);
static int DebugNearestNodeList2(float *pos, PathNode **nodelist, int iMaxNodes);
static void ShowNodes(void);
static void LoadNodes(void);
static void CreatePaths(void);
static void *AllocPathNode(void);
static void FreePathNode(void *);
static void ResetNodes(void);
static void UpdatePathwaysForBadPlace(const Vector &origin, float radius, int dir, int team);
static PathInfo *GeneratePath(PathInfo *path);
static PathInfo *GeneratePathNear(PathInfo *path);
static PathInfo *GeneratePathAway(PathInfo *path);
static class PathNode *GetSpawnNode(ClassDef *cls);
static int FindPath(
float *start, float *end, Entity *ent, float maxPath, float *vLeashHome, float fLeashDistSquared, int fallheight
);
static int FindPathAway(
float *start,
float *avoid,
float *vPreferredDir,
Entity *ent,
float fMinSafeDist,
float *vLeashHome,
float fLeashDistSquared,
int fallheight
);
static int FindPathNear(
float *start,
float *end,
Entity *ent,
float maxPath,
float fRadiusSquared,
float *vLeashHome,
float fLeashDistSquared,
int fallheight
);
static class PathNode *
FindCornerNodeForWall(float *start, float *end, class SimpleActor *ent, float maxPath, float *plane);
static class PathNode *FindCornerNodeForExactPath(class SimpleActor *self, Sentient *enemy, float fMaxPath);
static int
FindPotentialCover(class SimpleActor *pEnt, Vector& vPos, Entity *pEnemy, PathNode **ppFoundNodes, int iMaxFind);
static void PlayerCover(class Player *pPlayer);
static class PathNode *FindNearestCover(class SimpleActor *pEnt, Vector& vPos, Entity *pEnemy);
static class PathNode *FindNearestSniperNode(class SimpleActor *pEnt, Vector& vPos, Entity *pEnemy);
2016-03-27 11:49:47 +02:00
private:
2023-10-22 21:06:43 +02:00
static int NearestNodeSetup(vec3_t pos, MapCell *cell, int *nodes, vec3_t *deltas);
2016-03-27 11:49:47 +02:00
};
extern PathSearch PathManager;
2023-10-22 21:06:43 +02:00
PathNode *AI_FindNode(const char *name);
void AI_AddNode(PathNode *node);
void AI_RemoveNode(PathNode *node);
void AI_ResetNodes(void);
2016-03-27 11:49:47 +02:00
class AttractiveNode : public SimpleArchivedEntity
{
public:
2023-10-22 21:06:43 +02:00
int m_iPriority;
bool m_bUse;
float m_fMaxStayTime;
float m_fMaxDistance;
float m_fMaxDistanceSquared;
float m_fRespawnTime;
const_str m_csTeam;
int m_iTeam;
2016-03-27 11:49:47 +02:00
private:
2023-10-22 21:06:43 +02:00
// Container< SafePtr< Sentient > > m_pSentList;
2016-03-27 11:49:47 +02:00
public:
2023-10-22 21:06:43 +02:00
CLASS_PROTOTYPE(AttractiveNode);
AttractiveNode();
~AttractiveNode();
bool CheckTeam(Sentient *sent);
void setMaxDist(float dist);
void GetPriority(Event *ev);
void SetPriority(Event *ev);
void GetDistance(Event *ev);
void SetDistance(Event *ev);
void GetStayTime(Event *ev);
void SetStayTime(Event *ev);
void GetRespawnTime(Event *ev);
void SetRespawnTime(Event *ev);
void GetTeam(Event *ev);
void SetTeam(Event *ev);
void SetUse(Event *ev);
void Archive(Archiver& arc) override;
2016-03-27 11:49:47 +02:00
};
2023-10-22 21:06:43 +02:00
typedef SafePtr<AttractiveNode> AttractiveNodePtr;
2016-03-27 11:49:47 +02:00
2023-10-22 21:06:43 +02:00
inline void AttractiveNode::Archive(Archiver& arc)
2016-03-27 11:49:47 +02:00
{
2023-10-22 21:06:43 +02:00
arc.ArchiveInteger(&m_iPriority);
arc.ArchiveBool(&m_bUse);
arc.ArchiveFloat(&m_fMaxStayTime);
arc.ArchiveFloat(&m_fMaxDistanceSquared);
2016-03-27 11:49:47 +02:00
}
2023-10-22 21:06:43 +02:00
extern Container<AttractiveNode *> attractiveNodes;