Improved bot door usage

This commit is contained in:
RGreenlees 2023-10-16 23:05:07 +01:00 committed by pierow
parent b7db5adcaa
commit e72addc6d1
12 changed files with 308 additions and 119 deletions

View file

@ -416,6 +416,7 @@ typedef struct _NAV_STATUS
Vector TargetDestination = g_vecZero; // Desired destination
Vector ActualMoveDestination = g_vecZero; // Actual destination on nav mesh
Vector PathDestination = g_vecZero; // Where the path is currently headed to
Vector LastNavMeshPosition = g_vecZero; // Tracks the last place the bot was on the nav mesh. Useful if accidentally straying off it
@ -458,6 +459,9 @@ typedef struct _NAV_STATUS
nav_profile NavProfile;
bool bNavProfileChanged = false;
unsigned short SpecialMovementFlags = 0; // Any special movement flags required for this path (e.g. needs a welder, needs a jetpack etc.)
} nav_status;
// Type of goal the commander wants to achieve

View file

@ -2,6 +2,7 @@
#include "AvHAIMath.h"
#include "AvHAIPlayerUtil.h"
#include "AvHAITactical.h"
#include "AvHAINavigation.h"
#include "../AvHGamerules.h"
@ -243,6 +244,41 @@ bool GetNearestMapLocationAtPoint(vec3_t SearchLocation, string& outLocation)
return theSuccess;
}
void AIDEBUG_DrawBotPath(AvHAIPlayer* pBot)
{
if (pBot->BotNavInfo.PathSize == 0) { return; }
for (int i = 0; i < pBot->BotNavInfo.PathSize; i++)
{
Vector FromLoc = pBot->BotNavInfo.CurrentPath[i].FromLocation;
Vector ToLoc = pBot->BotNavInfo.CurrentPath[i].Location;
switch (pBot->BotNavInfo.CurrentPath[i].flag)
{
case SAMPLE_POLYFLAGS_WELD:
case SAMPLE_POLYFLAGS_DOOR:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, 255, 0, 0);
break;
case SAMPLE_POLYFLAGS_JUMP:
case SAMPLE_POLYFLAGS_DUCKJUMP:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, 255, 255, 0);
break;
case SAMPLE_POLYFLAGS_LADDER:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, 0, 0, 255);
break;
case SAMPLE_POLYFLAGS_WALLCLIMB:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, 0, 128, 0);
break;
case SAMPLE_POLYFLAGS_BLOCKED:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, 128, 128, 128);
break;
default:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc);
break;
}
}
}
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end)
{
if (FNullEnt(pEntity) || pEntity->free) { return; }

View file

@ -30,6 +30,8 @@ bool GetNearestMapLocationAtPoint(vec3_t SearchLocation, string& outLocation);
AvHAIDeployableStructureType GetDeployableObjectTypeFromEdict(const edict_t* StructureEdict);
void AIDEBUG_DrawBotPath(AvHAIPlayer* pBot);
// Draws a white line between start and end for the given player (pEntity) for 0.1s
void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end);
// Draws a white line between start and end for the given player (pEntity) for given number of seconds

View file

@ -36,6 +36,9 @@ vector<nav_door> NavDoors;
nav_weldable NavWeldableObstacles[32];
int NumWeldableObstacles;
nav_mesh NavMeshes[MAX_NAV_MESHES]; // Array of nav meshes. Currently only 3 are used (building, onos, and regular)
nav_profile BaseNavProfiles[MAX_NAV_PROFILES]; // Array of nav profiles
struct NavMeshSetHeader
{
int magic;
@ -276,9 +279,14 @@ struct MeshProcess : public dtTileCacheMeshProcess
}
else if (polyAreas[i] == DT_TILECACHE_WELD_AREA)
{
polyAreas[i] = SAMPLE_POLYAREA_GROUND;
polyAreas[i] = SAMPLE_POLYAREA_OBSTRUCTION;
polyFlags[i] = SAMPLE_POLYFLAGS_WELD;
}
else if (polyAreas[i] == DT_TILECACHE_DOOR_AREA)
{
polyAreas[i] = SAMPLE_POLYAREA_OBSTRUCTION;
polyFlags[i] = SAMPLE_POLYFLAGS_DOOR;
}
}
params->offMeshConAreas = OffMeshAreas;
@ -545,6 +553,8 @@ void UnloadNavigationData()
bool LoadNavMesh(const char* mapname)
{
memset(NavMeshes, 0, sizeof(NavMeshes));
char filename[256]; // Full path to BSP file
GetFullFilePath(filename, mapname);
@ -882,10 +892,13 @@ bool LoadNavMesh(const char* mapname)
void UTIL_PopulateBaseNavProfiles()
{
memset(BaseNavProfiles, 0, sizeof(BaseNavProfiles));
BaseNavProfiles[MARINE_BASE_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH;
BaseNavProfiles[MARINE_BASE_NAV_PROFILE].bFlyingProfile = false;
BaseNavProfiles[MARINE_BASE_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_MARINE;
BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f);
BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_OBSTRUCTION, 2.0f);
BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 2.0f);
BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 2.0f);
BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALLDAMAGE, 10.0f);
@ -899,6 +912,7 @@ void UTIL_PopulateBaseNavProfiles()
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setExcludeFlags(0);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_OBSTRUCTION, 2.0f);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 1.0f);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALLDAMAGE, 1.0f);
@ -912,6 +926,7 @@ void UTIL_PopulateBaseNavProfiles()
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].bFlyingProfile = false;
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_MARINE;
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_OBSTRUCTION, 2.0f);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 2.0f);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALLDAMAGE, 10.0f);
@ -926,6 +941,7 @@ void UTIL_PopulateBaseNavProfiles()
BaseNavProfiles[LERK_BASE_NAV_PROFILE].bFlyingProfile = true;
BaseNavProfiles[LERK_BASE_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_SKULK;
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_OBSTRUCTION, 2.0f);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 1.0f);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALLDAMAGE, 1.0f);
@ -939,6 +955,7 @@ void UTIL_PopulateBaseNavProfiles()
BaseNavProfiles[FADE_BASE_NAV_PROFILE].bFlyingProfile = false;
BaseNavProfiles[FADE_BASE_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_SKULK;
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_OBSTRUCTION, 2.0f);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.5f);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 1.0f);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALLDAMAGE, 1.0f);
@ -952,6 +969,7 @@ void UTIL_PopulateBaseNavProfiles()
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].bFlyingProfile = false;
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_ONOS;
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_OBSTRUCTION, 2.0f);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 2.0f);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 1.0f);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALLDAMAGE, 10.0f);
@ -965,12 +983,24 @@ void UTIL_PopulateBaseNavProfiles()
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].NavMeshIndex = BUILDING_NAV_MESH;
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF);
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].Filters.setExcludeFlags(0);
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f);
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_OBSTRUCTION, 1.0f);
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f);
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 1.0f);
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALLDAMAGE, 1.0f);
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_WALLCLIMB, 1.0f);
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].bFlyingProfile = false;
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_MARINE;
BaseNavProfiles[ALL_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH;
BaseNavProfiles[ALL_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF);
BaseNavProfiles[ALL_NAV_PROFILE].Filters.setExcludeFlags(0);
BaseNavProfiles[ALL_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f);
BaseNavProfiles[ALL_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_OBSTRUCTION, 1.0f);
BaseNavProfiles[ALL_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f);
BaseNavProfiles[ALL_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 1.0f);
BaseNavProfiles[ALL_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALLDAMAGE, 1.0f);
BaseNavProfiles[ALL_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_WALLCLIMB, 1.0f);
BaseNavProfiles[ALL_NAV_PROFILE].bFlyingProfile = false;
BaseNavProfiles[ALL_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_SKULK;
}
@ -1702,6 +1732,7 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle,
const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(pBot->BotNavInfo.NavProfile);
const dtQueryFilter* m_navFilter = &pBot->BotNavInfo.NavProfile.Filters;
bool bHasWelder = !(m_navFilter->getExcludeFlags() & SAMPLE_POLYFLAGS_WELD);
if (!m_navQuery || !m_navMesh || !m_navFilter || vIsZero(FromLocation) || vIsZero(ToLocation))
{
@ -1802,6 +1833,8 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle,
TraceResult hit;
Vector TraceStart;
pBot->BotNavInfo.SpecialMovementFlags = 0;
Vector NodeFromLocation = Vector(StartNearest[0], -StartNearest[2], StartNearest[1]);
for (int nVert = 0; nVert < nVertCount; nVert++)
@ -1841,6 +1874,8 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle,
}
}
pBot->BotNavInfo.SpecialMovementFlags |= CurrFlags;
// End alignment to floor
// For ladders and wall climbing, calculate the climb height needed to complete the move.
@ -1864,12 +1899,12 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle,
path[(nVert)].requiredZ = path[(nVert)].Location.z;
}
path[(nVert)].flag = straightPathFlags[nVert];
path[(nVert)].flag = CurrFlags;
path[(nVert)].area = CurrArea;
path[(nVert)].poly = StraightPolyPath[nVert];
m_navMesh->getPolyFlags(StraightPolyPath[nVert], &CurrFlags);
m_navMesh->getPolyArea(StraightPolyPath[0], &CurrArea);
m_navMesh->getPolyArea(StraightPolyPath[nVert], &CurrArea);
CurrFlags &= ~(SAMPLE_POLYFLAGS_TEAM1STRUCTURE | SAMPLE_POLYFLAGS_TEAM2STRUCTURE);
@ -2020,31 +2055,18 @@ bool HasBotReachedPathPoint(const AvHAIPlayer* pBot)
return false;
}
void CheckAndHandleDoorObstruction(AvHAIPlayer* pBot, const Vector MoveFrom, const Vector MoveTo)
void CheckAndHandleDoorObstruction(AvHAIPlayer* pBot)
{
int PathNodeIndex = pBot->BotNavInfo.CurrentPathPoint + 1;
edict_t* BlockingDoorEdict = UTIL_GetDoorBlockingPathPoint(pBot->Edict->v.origin, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].Location, SAMPLE_POLYAREA_GROUND, nullptr);
if (FNullEnt(BlockingDoorEdict))
while (FNullEnt(BlockingDoorEdict) && PathNodeIndex < pBot->BotNavInfo.PathSize - 1 && PathNodeIndex <= pBot->BotNavInfo.CurrentPathPoint + 2)
{
if (pBot->BotNavInfo.CurrentPathPoint < pBot->BotNavInfo.PathSize - 1)
{
BlockingDoorEdict = UTIL_GetDoorBlockingPathPoint(&pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1], nullptr);
}
BlockingDoorEdict = UTIL_GetDoorBlockingPathPoint(pBot, &pBot->BotNavInfo.CurrentPath[PathNodeIndex], nullptr);
PathNodeIndex++;
}
if (FNullEnt(BlockingDoorEdict))
{
if (pBot->BotNavInfo.CurrentPathPoint < pBot->BotNavInfo.PathSize - 2)
{
BlockingDoorEdict = UTIL_GetDoorBlockingPathPoint(&pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 2], nullptr);
}
}
if (FNullEnt(BlockingDoorEdict))
{
return;
}
if (FNullEnt(BlockingDoorEdict)) { return; }
CBaseToggle* BlockingDoor = GetClassPtr((CBaseToggle*)VARS(BlockingDoorEdict));
@ -2138,7 +2160,7 @@ void CheckAndHandleDoorObstruction(AvHAIPlayer* pBot, const Vector MoveFrom, con
}
edict_t* UTIL_GetDoorBlockingPathPoint(bot_path_node* PathNode, edict_t* SearchDoor)
edict_t* UTIL_GetDoorBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* PathNode, edict_t* SearchDoor)
{
if (!PathNode) { return nullptr; }
@ -2151,7 +2173,7 @@ edict_t* UTIL_GetDoorBlockingPathPoint(bot_path_node* PathNode, edict_t* SearchD
{
Vector TargetLoc = Vector(FromLoc.x, FromLoc.y, PathNode->requiredZ);
UTIL_TraceLine(FromLoc, TargetLoc, ignore_monsters, dont_ignore_glass, nullptr, &doorHit);
UTIL_TraceLine(FromLoc, TargetLoc, ignore_monsters, dont_ignore_glass, (pBot!= nullptr) ? pBot->Edict->v.pContainingEntity : nullptr, &doorHit);
if (!FNullEnt(SearchDoor))
{
@ -2173,7 +2195,7 @@ edict_t* UTIL_GetDoorBlockingPathPoint(bot_path_node* PathNode, edict_t* SearchD
Vector TargetLoc2 = Vector(ToLoc.x, ToLoc.y, PathNode->requiredZ);
UTIL_TraceLine(TargetLoc, TargetLoc2, ignore_monsters, dont_ignore_glass, nullptr, &doorHit);
UTIL_TraceLine(TargetLoc, TargetLoc2, ignore_monsters, dont_ignore_glass, (pBot != nullptr) ? pBot->Edict->v.pContainingEntity : nullptr, &doorHit);
if (!FNullEnt(SearchDoor))
{
@ -2197,7 +2219,7 @@ edict_t* UTIL_GetDoorBlockingPathPoint(bot_path_node* PathNode, edict_t* SearchD
{
Vector TargetLoc = Vector(ToLoc.x, ToLoc.y, FromLoc.z);
UTIL_TraceLine(FromLoc, TargetLoc, ignore_monsters, dont_ignore_glass, nullptr, &doorHit);
UTIL_TraceLine(FromLoc, TargetLoc, ignore_monsters, dont_ignore_glass, (pBot != nullptr) ? pBot->Edict->v.pContainingEntity : nullptr, &doorHit);
if (!FNullEnt(SearchDoor))
{
@ -2216,7 +2238,7 @@ edict_t* UTIL_GetDoorBlockingPathPoint(bot_path_node* PathNode, edict_t* SearchD
}
}
UTIL_TraceLine(TargetLoc, ToLoc + Vector(0.0f, 0.0f, 10.0f), ignore_monsters, dont_ignore_glass, nullptr, &doorHit);
UTIL_TraceLine(TargetLoc, ToLoc + Vector(0.0f, 0.0f, 10.0f), ignore_monsters, dont_ignore_glass, (pBot != nullptr) ? pBot->Edict->v.pContainingEntity : nullptr, &doorHit);
if (!FNullEnt(SearchDoor))
{
@ -2235,8 +2257,10 @@ edict_t* UTIL_GetDoorBlockingPathPoint(bot_path_node* PathNode, edict_t* SearchD
}
}
}
Vector StartTrace = FromLoc + Vector(0.0f, 0.0f, 16.0f);
Vector EndTrace = ToLoc + Vector(0.0f, 0.0f, 16.0f);
UTIL_TraceLine(FromLoc + Vector(0.0f, 0.0f, 16.0f), ToLoc + Vector(0.0f, 0.0f, 16.0f), ignore_monsters, dont_ignore_glass, nullptr, &doorHit);
UTIL_TraceLine(StartTrace, EndTrace, ignore_monsters, dont_ignore_glass, (pBot != nullptr) ? pBot->Edict->v.pContainingEntity : nullptr, &doorHit);
if (!FNullEnt(SearchDoor))
{
@ -2271,7 +2295,6 @@ edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* Pa
Vector TargetLoc = Vector(FromLoc.x, FromLoc.y, PathNode->requiredZ);
UTIL_TraceLine(FromLoc, TargetLoc, dont_ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &breakableHit);
UTIL_DrawLine(INDEXENT(1), FromLoc, TargetLoc);
if (!FNullEnt(SearchBreakable))
{
@ -2292,7 +2315,6 @@ edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* Pa
Vector TargetLoc2 = Vector(ToLoc.x, ToLoc.y, PathNode->requiredZ);
UTIL_TraceLine(TargetLoc, TargetLoc2, dont_ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &breakableHit);
UTIL_DrawLine(INDEXENT(1), TargetLoc, TargetLoc2);
if (!FNullEnt(SearchBreakable))
{
@ -2315,7 +2337,6 @@ edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* Pa
Vector TargetLoc = Vector(ToLoc.x, ToLoc.y, FromLoc.z);
UTIL_TraceLine(FromLoc, TargetLoc, dont_ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &breakableHit);
UTIL_DrawLine(INDEXENT(1), FromLoc, TargetLoc);
if (!FNullEnt(SearchBreakable))
{
@ -2333,7 +2354,6 @@ edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* Pa
}
UTIL_TraceLine(TargetLoc, ToLoc + Vector(0.0f, 0.0f, 10.0f), dont_ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &breakableHit);
UTIL_DrawLine(INDEXENT(1), TargetLoc, ToLoc + Vector(0.0f, 0.0f, 10.0f));
if (!FNullEnt(SearchBreakable))
{
@ -2352,7 +2372,6 @@ edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* Pa
}
UTIL_TraceLine(FromLoc, ToLoc, dont_ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &breakableHit);
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc);
if (!FNullEnt(SearchBreakable))
@ -2386,7 +2405,6 @@ edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, const Vector From
Vector TargetLoc = Vector(FromLoc.x, FromLoc.y, ToLocation.z);
UTIL_TraceLine(FromLoc, TargetLoc, dont_ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &breakableHit);
UTIL_DrawLine(INDEXENT(1), FromLoc, TargetLoc);
if (!FNullEnt(SearchBreakable))
{
@ -2407,7 +2425,6 @@ edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, const Vector From
Vector TargetLoc2 = Vector(ToLoc.x, ToLoc.y, ToLocation.z);
UTIL_TraceLine(TargetLoc, TargetLoc2, dont_ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &breakableHit);
UTIL_DrawLine(INDEXENT(1), TargetLoc, TargetLoc2);
if (!FNullEnt(SearchBreakable))
{
@ -2430,7 +2447,6 @@ edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, const Vector From
Vector TargetLoc = Vector(ToLoc.x, ToLoc.y, FromLoc.z);
UTIL_TraceLine(FromLoc, TargetLoc, dont_ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &breakableHit);
UTIL_DrawLine(INDEXENT(1), FromLoc, TargetLoc);
if (!FNullEnt(SearchBreakable))
{
@ -2448,7 +2464,6 @@ edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, const Vector From
}
UTIL_TraceLine(TargetLoc, ToLoc + Vector(0.0f, 0.0f, 10.0f), dont_ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &breakableHit);
UTIL_DrawLine(INDEXENT(1), TargetLoc, ToLoc + Vector(0.0f, 0.0f, 10.0f));
if (!FNullEnt(SearchBreakable))
{
@ -2467,7 +2482,6 @@ edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, const Vector From
}
UTIL_TraceLine(FromLoc, ToLoc, dont_ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &breakableHit);
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc);
if (!FNullEnt(SearchBreakable))
{
@ -2615,7 +2629,7 @@ bool UTIL_IsPathBlockedByDoor(const Vector StartLoc, const Vector EndLoc, edict_
if (!ValidNavmeshPoint)
{
return g_vecZero;
return false;
}
bot_path_node Path[MAX_AI_PATH_SIZE];
@ -2630,7 +2644,7 @@ bool UTIL_IsPathBlockedByDoor(const Vector StartLoc, const Vector EndLoc, edict_
{
for (int i = 1; i < PathSize; i++)
{
if (UTIL_GetDoorBlockingPathPoint(&Path[i], SearchDoor) != nullptr)
if (UTIL_GetDoorBlockingPathPoint(nullptr, &Path[i], SearchDoor) != nullptr)
{
return true;
}
@ -2846,11 +2860,7 @@ void NewMove(AvHAIPlayer* pBot)
// While moving, check to make sure we're not obstructed by a func_breakable, e.g. vent or window.
CheckAndHandleBreakableObstruction(pBot, MoveFrom, MoveTo);
if (gpGlobals->time - pBot->LastUseTime >= 1.0f)
{
CheckAndHandleDoorObstruction(pBot, MoveFrom, MoveTo);
}
CheckAndHandleDoorObstruction(pBot);
}
@ -4506,7 +4516,6 @@ void SetBaseNavProfile(AvHAIPlayer* pBot)
void UpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle)
{
pBot->BotNavInfo.bNavProfileChanged = false;
if (IsPlayerMarine(pBot->Player))
{
@ -4549,6 +4558,7 @@ void MarineUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle)
bHasWelder = (NearbyWelder != nullptr);
}
// Did our nav profile previously indicate we could go through weldable doors?
bool bHadWelder = !(NavProfile->Filters.getExcludeFlags() & SAMPLE_POLYFLAGS_WELD);
if (bHasWelder != bHadWelder)
@ -4695,38 +4705,7 @@ void OnosUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle)
bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle MoveStyle, const float MaxAcceptableDist)
{
nav_status* BotNavInfo = &pBot->BotNavInfo;
bool bHasMovementTask = (BotNavInfo->MovementTask.TaskType != TASK_NONE);
bool bIsPerformingMovementTask = false;
if (bHasMovementTask)
{
bIsPerformingMovementTask = (vEquals(Destination, BotNavInfo->MovementTask.TaskLocation) || (!FNullEnt(BotNavInfo->MovementTask.TaskTarget) && vEquals(Destination, BotNavInfo->MovementTask.TaskTarget->v.origin)) || (!FNullEnt(BotNavInfo->MovementTask.TaskSecondaryTarget) && vEquals(Destination, BotNavInfo->MovementTask.TaskSecondaryTarget->v.origin)));
}
// Invalid destination, or we're already there
if (!bIsPerformingMovementTask && (vIsZero(Destination) || BotIsAtLocation(pBot, Destination)))
{
ClearBotMovement(pBot);
return true;
}
if (bHasMovementTask && !bIsPerformingMovementTask)
{
if (AITASK_IsTaskStillValid(pBot, &BotNavInfo->MovementTask))
{
BotProgressTask(pBot, &BotNavInfo->MovementTask);
return true;
}
else
{
AITASK_ClearBotTask(pBot, &BotNavInfo->MovementTask);
}
}
UTIL_UpdateBotMovementStatus(pBot);
// If we are currently in the process of getting back on the navmesh, don't interrupt
if (BotNavInfo->UnstuckMoveLocation != g_vecZero)
{
@ -4769,45 +4748,82 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
pBot->Button |= IN_DUCK;
}
return true;
}
}
UpdateBotMoveProfile(pBot, MoveStyle);
UTIL_UpdateBotMovementStatus(pBot);
bool bIsFlyingProfile = pBot->BotNavInfo.NavProfile.bFlyingProfile;
bool bNavProfileChanged = pBot->BotNavInfo.bNavProfileChanged;
if (BotNavInfo->PathSize > 0)
{
bool bNavProfileChanged = pBot->BotNavInfo.bNavProfileChanged;
bool bHasMovementTask = (BotNavInfo->MovementTask.TaskType != TASK_NONE);
Vector MoveTaskDestination = g_vecZero;
if (bHasMovementTask)
{
MoveTaskDestination = (!vIsZero(BotNavInfo->MovementTask.TaskLocation)) ? BotNavInfo->MovementTask.TaskLocation : BotNavInfo->MovementTask.TaskTarget->v.origin;
}
bool bUltimateDestinationChanged = !vEquals(Destination, BotNavInfo->TargetDestination, GetPlayerRadius(pBot->Player)) && !vEquals(Destination, MoveTaskDestination);
bool bHasReachedDestination = BotIsAtLocation(pBot, BotNavInfo->TargetDestination);
if (bUltimateDestinationChanged || bNavProfileChanged || bHasReachedDestination)
{
// First abort our current move so we don't try to recalculate half-way up a wall or ladder
if (bIsFlyingProfile || AbortCurrentMove(pBot, Destination))
{
ClearBotPath(pBot);
return true;
}
}
else
{
if (bHasMovementTask && !vEquals(Destination, MoveTaskDestination))
{
if (AITASK_IsTaskStillValid(pBot, &BotNavInfo->MovementTask))
{
BotProgressTask(pBot, &BotNavInfo->MovementTask);
return true;
}
else
{
AITASK_ClearBotTask(pBot, &BotNavInfo->MovementTask);
}
}
}
}
bool bCanRecalculatePath = (gpGlobals->time - pBot->BotNavInfo.LastPathCalcTime > MIN_PATH_RECALC_TIME);
bool bDestinationChanged = (!vEquals(Destination, BotNavInfo->TargetDestination, GetPlayerRadius(pBot->Player)));
// Only recalculate the path if there isn't a path, or something has changed and enough time has elapsed since the last path calculation
bool bShouldCalculatePath = bCanRecalculatePath && (BotNavInfo->PathSize == 0 || (bNavProfileChanged || bDestinationChanged || BotNavInfo->bPendingRecalculation));
bool bShouldCalculatePath = bCanRecalculatePath && (BotNavInfo->PathSize == 0 || !vEquals(Destination, BotNavInfo->PathDestination));
if (bShouldCalculatePath)
{
// First abort our current move so we don't try to recalculate half-way up a wall or ladder
if (!bIsFlyingProfile && !AbortCurrentMove(pBot, Destination))
{
return true;
}
if (pBot->Player->IsOnLadder())
{
BotJump(pBot);
return true;
}
if (bDestinationChanged && !bIsPerformingMovementTask)
{
AITASK_ClearBotTask(pBot, &pBot->BotNavInfo.MovementTask);
}
pBot->BotNavInfo.LastPathCalcTime = gpGlobals->time;
BotNavInfo->bPendingRecalculation = false;
BotNavInfo->TargetDestination = Destination;
if (vIsZero(BotNavInfo->TargetDestination))
{
BotNavInfo->TargetDestination = Destination;
}
BotNavInfo->PathDestination = Destination;
Vector ValidNavmeshPoint = UTIL_ProjectPointToNavmesh(Destination, Vector(max_ai_use_reach, max_ai_use_reach, max_ai_use_reach), pBot->BotNavInfo.NavProfile);
@ -4828,8 +4844,6 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
{
PathFindingStatus = FindPathClosestToPoint(pBot, pBot->BotNavInfo.MoveStyle, pBot->CurrentFloorPosition, ValidNavmeshPoint, BotNavInfo->CurrentPath, &BotNavInfo->PathSize, MaxAcceptableDist);
}
if (dtStatusSucceed(PathFindingStatus))
{
@ -5162,10 +5176,7 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
CheckAndHandleBreakableObstruction(pBot, MoveFrom, CurrentMoveDest);
if (gpGlobals->time - pBot->LastUseTime >= 3.0f)
{
CheckAndHandleDoorObstruction(pBot, MoveFrom, CurrentMoveDest);
}
CheckAndHandleDoorObstruction(pBot);
}
void BotFollowPath(AvHAIPlayer* pBot)
@ -5204,6 +5215,25 @@ void BotFollowPath(AvHAIPlayer* pBot)
return;
}
// If this path requires use of a welder and we don't have one, then find one
if ((pBot->BotNavInfo.SpecialMovementFlags & SAMPLE_POLYFLAGS_WELD) && !PlayerHasWeapon(pBot->Player, WEAPON_MARINE_WELDER))
{
if (pBot->BotNavInfo.MovementTask.TaskType != TASK_GET_WEAPON)
{
AITASK_ClearBotTask(pBot, &pBot->BotNavInfo.MovementTask);
AvHAIDroppedItem* NearestWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, 0.0f, 0.0f, true);
if (NearestWelder)
{
AITASK_SetPickupTask(pBot, &pBot->BotNavInfo.MovementTask, NearestWelder->edict, true);
return;
}
}
}
Vector TargetMoveLocation = BotNavInfo->CurrentPath[BotNavInfo->CurrentPathPoint].Location;
bool bIsUsingPhaseGate = (BotNavInfo->CurrentPath[BotNavInfo->CurrentPathPoint].flag == SAMPLE_POLYFLAGS_PHASEGATE);
@ -5888,8 +5918,15 @@ void ClearBotPath(AvHAIPlayer* pBot)
memset(pBot->BotNavInfo.CurrentPath, 0, sizeof(pBot->BotNavInfo.CurrentPath));
}
pBot->BotNavInfo.SpecialMovementFlags = 0;
AITASK_ClearBotTask(pBot, &pBot->BotNavInfo.MovementTask);
pBot->BotNavInfo.bNavProfileChanged = false;
pBot->BotNavInfo.TargetDestination = g_vecZero;
pBot->BotNavInfo.PathDestination = g_vecZero;
//pBot->BotNavInfo.LastNavMeshPosition = g_vecZero;
}
@ -6104,9 +6141,24 @@ Vector UTIL_GetFurthestVisiblePointOnPath(const Vector ViewerLocation, const bot
Vector UTIL_GetButtonFloorLocation(const Vector UserLocation, edict_t* ButtonEdict)
{
Vector ClosestPoint = UTIL_GetClosestPointOnEntityToLocation(UserLocation, ButtonEdict);
Vector ClosestPoint = g_vecZero;
if (ButtonEdict->v.size.x > 64.0f || ButtonEdict->v.size.y > 64.0f)
{
ClosestPoint = UTIL_GetClosestPointOnEntityToLocation(UserLocation, ButtonEdict);
}
else
{
ClosestPoint = UTIL_GetCentreOfEntity(ButtonEdict);
}
Vector ButtonAccessPoint = UTIL_ProjectPointToNavmesh(ClosestPoint, Vector(100.0f, 100.0f, 100.0f), BaseNavProfiles[ALL_NAV_PROFILE]);
nav_profile ButtonNavProfile;
memcpy(&ButtonNavProfile, &BaseNavProfiles[ALL_NAV_PROFILE], sizeof(nav_profile));
ButtonNavProfile.Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD);
ButtonNavProfile.Filters.addExcludeFlags(SAMPLE_POLYFLAGS_DOOR);
Vector ButtonAccessPoint = UTIL_ProjectPointToNavmesh(ClosestPoint, Vector(100.0f, 100.0f, 100.0f), ButtonNavProfile);
if (vIsZero(ButtonAccessPoint))
{
@ -6124,7 +6176,7 @@ Vector UTIL_GetButtonFloorLocation(const Vector UserLocation, edict_t* ButtonEdi
PlayerAccessLoc.z += 36.0f;
}
if (fabsf(PlayerAccessLoc.z - ClosestPoint.z) <= 60.0f)
if (fabsf(PlayerAccessLoc.z - ClosestPoint.z) <= max_player_use_reach)
{
return ButtonAccessPoint;
}
@ -6140,7 +6192,7 @@ Vector UTIL_GetButtonFloorLocation(const Vector UserLocation, edict_t* ButtonEdi
NewProjection = ClosestPoint + Vector(0.0f, 0.0f, 100.0f);
}
Vector NewButtonAccessPoint = UTIL_ProjectPointToNavmesh(NewProjection, BaseNavProfiles[ALL_NAV_PROFILE]);
Vector NewButtonAccessPoint = UTIL_ProjectPointToNavmesh(NewProjection, ButtonNavProfile);
if (vIsZero(NewButtonAccessPoint))
{
@ -6524,11 +6576,14 @@ void UTIL_UpdateDoors(bool bInitial)
{
UTIL_ApplyTempObstaclesToDoor(&(*it), DT_TILECACHE_NULL_AREA);
}
if (it->ActivationType == DOOR_WELD)
else if (it->ActivationType == DOOR_WELD)
{
UTIL_ApplyTempObstaclesToDoor(&(*it), DT_TILECACHE_WELD_AREA);
}
else
{
UTIL_ApplyTempObstaclesToDoor(&(*it), DT_TILECACHE_DOOR_AREA);
}
it->CurrentState = DoorRef->m_toggle_state;
}
@ -6611,7 +6666,7 @@ void UTIL_ApplyTempObstaclesToDoor(nav_door* DoorRef, const int Area)
for (int ii = 0; ii < NumObstacles; ii++)
{
UTIL_AddTemporaryObstacles(CurrentPoint, CylinderRadius, SizeZ, Area, DoorRef->ObstacleRefs[ii]);
UTIL_AddTemporaryObstacles(CurrentPoint, CylinderRadius, SizeZ * 2.0f, Area, DoorRef->ObstacleRefs[ii]);
if (bUseXAxis)
{
@ -6623,7 +6678,6 @@ void UTIL_ApplyTempObstaclesToDoor(nav_door* DoorRef, const int Area)
}
}
}
void UTIL_UpdateDoorTriggers(nav_door* Door)
@ -6742,6 +6796,7 @@ void UTIL_PopulateDoors()
UTIL_PopulateTriggersForEntity(currDoor->edict(), NewDoor.TriggerEnts);
}
NavDoors.push_back(NewDoor);
}
currDoor = NULL;
@ -6767,6 +6822,8 @@ void UTIL_PopulateDoors()
UTIL_PopulateTriggersForEntity(currDoor->edict(), NewDoor.TriggerEnts);
}
NavDoors.push_back(NewDoor);
}
UTIL_UpdateDoors(true);

View file

@ -20,7 +20,7 @@
*/
constexpr auto MIN_PATH_RECALC_TIME = 0.33f; // How frequently can a bot recalculate its path? Default to max 3 times per second
constexpr auto MAX_BOT_STUCK_TIME = 30.0f; // How long a bot can be stuck, unable to move, before giving up and suiciding
constexpr auto MAX_BOT_STUCK_TIME = 0.0f; // How long a bot can be stuck, unable to move, before giving up and suiciding
constexpr auto MARINE_BASE_NAV_PROFILE = 0;
constexpr auto SKULK_BASE_NAV_PROFILE = 1;
@ -40,7 +40,8 @@ enum SamplePolyAreas
SAMPLE_POLYAREA_CROUCH = 1, // Requires crouched movement
SAMPLE_POLYAREA_BLOCKED = 2, // Requires a jump to get over
SAMPLE_POLYAREA_FALLDAMAGE = 3, // Requires taking fall damage (if not immune to it)
SAMPLE_POLYAREA_WALLCLIMB = 4 // Requires the ability to wall-stick, fly or blink
SAMPLE_POLYAREA_WALLCLIMB = 4, // Requires the ability to wall-stick, fly or blink
SAMPLE_POLYAREA_OBSTRUCTION = 5 // There is a door or weldable object in the way
};
// Possible movement types. Swim and door are not used
@ -58,6 +59,7 @@ enum SamplePolyFlags
SAMPLE_POLYFLAGS_TEAM1STRUCTURE = 1 << 9, // A team 1 structure is in the way that cannot be jumped over. Impassable to team 1 players
SAMPLE_POLYFLAGS_TEAM2STRUCTURE = 1 << 10, // A team 2 structure is in the way that cannot be jumped over. Impassable to team 2 players
SAMPLE_POLYFLAGS_WELD = 1 << 11, // Requires a welder to get through here
SAMPLE_POLYFLAGS_DOOR = 1 << 12, // Requires a welder to get through here
SAMPLE_POLYFLAGS_DISABLED = 1 << 15, // Disabled, not usable by anyone
SAMPLE_POLYFLAGS_ALL = 0xffff // All abilities.
@ -146,9 +148,6 @@ static const int DOOR_START_OPEN = 1;
static const float CHECK_STUCK_INTERVAL = 0.1f; // How frequently should the bot check if it's stuck?
static nav_mesh NavMeshes[MAX_NAV_MESHES]; // Array of nav meshes. Currently only 3 are used (building, onos, and regular)
static nav_profile BaseNavProfiles[MAX_NAV_PROFILES]; // Array of nav profiles
// Returns true if a valid nav mesh has been loaded into memory
bool NavmeshLoaded();
// Unloads all data, including loaded nav meshes, nav profiles, all the map data such as buildable structure maps and hive locations.
@ -244,12 +243,12 @@ void PhaseGateMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndP
// Will check for any func_breakable which might be in the way (e.g. window, vent) and make the bot aim and attack it to break it. Marines will switch to knife to break it.
void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom, const Vector MoveTo);
void CheckAndHandleDoorObstruction(AvHAIPlayer* pBot, const Vector MoveFrom, const Vector MoveTo);
void CheckAndHandleDoorObstruction(AvHAIPlayer* pBot);
DoorTrigger* UTIL_GetNearestDoorTrigger(const Vector Location, nav_door* Door, CBaseEntity* IgnoreTrigger);
bool UTIL_IsPathBlockedByDoor(const Vector StartLoc, const Vector EndLoc, edict_t* SearchDoor);
edict_t* UTIL_GetDoorBlockingPathPoint(bot_path_node* PathNode, edict_t* SearchDoor);
edict_t* UTIL_GetDoorBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* PathNode, edict_t* SearchDoor);
edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector ToLocation, const unsigned short MovementFlag, edict_t* SearchDoor);
edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* PathNode, edict_t* SearchBreakable);
edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, const Vector FromLocation, const Vector ToLocation, const unsigned short MovementFlag, edict_t* SearchBreakable);

View file

@ -11,6 +11,9 @@
#include "../AvHMessage.h"
extern nav_mesh NavMeshes[MAX_NAV_MESHES]; // Array of nav meshes. Currently only 3 are used (building, onos, and regular)
extern nav_profile BaseNavProfiles[MAX_NAV_PROFILES]; // Array of nav profiles
void BotJump(AvHAIPlayer* pBot)
{
if (pBot->BotNavInfo.IsOnGround)
@ -1450,6 +1453,11 @@ void StartNewBotFrame(AvHAIPlayer* pBot)
pBot->BotNavInfo.bShouldWalk = false;
if (pBot->BotNavInfo.NavProfile.ReachabilityFlag == AI_REACHABILITY_NONE)
{
SetBaseNavProfile(pBot);
}
}
void DroneThink(AvHAIPlayer* pBot)
@ -1462,6 +1470,8 @@ void DroneThink(AvHAIPlayer* pBot)
{
BotProgressTask(pBot, &pBot->PrimaryBotTask);
}
AIDEBUG_DrawBotPath(pBot);
}
void TestNavThink(AvHAIPlayer* pBot)

View file

@ -50,6 +50,9 @@ unsigned int ItemRefreshFrame = 0;
Vector TeamAStartingLocation = ZERO_VECTOR;
Vector TeamBStartingLocation = ZERO_VECTOR;
extern nav_mesh NavMeshes[MAX_NAV_MESHES]; // Array of nav meshes. Currently only 3 are used (building, onos, and regular)
extern nav_profile BaseNavProfiles[MAX_NAV_PROFILES]; // Array of nav profiles
bool AITAC_DeployableExistsAtLocation(const Vector& Location, const DeployableSearchFilter* Filter)
{
@ -164,6 +167,17 @@ AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocation(const Vector& Loc
return Result;
}
AvHAIDroppedItem* AITAC_GetDroppedItemRefFromEdict(edict_t* ItemEdict)
{
if (FNullEnt(ItemEdict)) { return nullptr; }
int EntIndex = ENTINDEX(ItemEdict);
if (EntIndex < 0) { return nullptr; }
return &MarineDroppedItemMap[EntIndex];
}
AvHAIDroppedItem* AITAC_FindClosestItemToLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance)
{
AvHAIDroppedItem* Result = NULL;

View file

@ -52,6 +52,8 @@ AvHAIResourceNode* AITAC_GetRandomResourceNode();
AvHAIDroppedItem* AITAC_FindClosestItemToLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance);
AvHAIDroppedItem* AITAC_GetDroppedItemRefFromEdict(edict_t* ItemEdict);
Vector AITAC_GetFloorLocationForHive(const AvHAIHiveDefinition* Hive);
int AITAC_GetNumHives();

View file

@ -14,6 +14,9 @@
#include "../AvHGamerules.h"
#include "../AvHWeldable.h"
extern nav_mesh NavMeshes[MAX_NAV_MESHES]; // Array of nav meshes. Currently only 3 are used (building, onos, and regular)
extern nav_profile BaseNavProfiles[MAX_NAV_PROFILES]; // Array of nav profiles
void AITASK_ClearAllBotTasks(AvHAIPlayer* pBot)
{
AITASK_ClearBotTask(pBot, &pBot->PrimaryBotTask);
@ -2626,6 +2629,59 @@ char* AITASK_TaskTypeToChar(const BotTaskType TaskType)
}
}
void AITASK_SetPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const bool bIsUrgent)
{
if (FNullEnt(Target) || (Target->v.effects & EF_NODRAW))
{
AITASK_ClearBotTask(pBot, Task);
return;
}
if (Task->TaskTarget == Target)
{
Task->bTaskIsUrgent = bIsUrgent;
return;
}
AvHAIDroppedItem* ItemToPickup = AITAC_GetDroppedItemRefFromEdict(Target);
if (!ItemToPickup || FNullEnt(ItemToPickup->edict) || !ItemToPickup->bIsReachableMarine)
{
AITASK_ClearBotTask(pBot, Task);
return;
}
Vector PickupLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, Target->v.origin, max_player_use_reach);
if (vIsZero(PickupLocation))
{
AITASK_ClearBotTask(pBot, Task);
return;
}
switch (ItemToPickup->ItemType)
{
case DEPLOYABLE_ITEM_AMMO:
Task->TaskType = TASK_GET_AMMO;
break;
case DEPLOYABLE_ITEM_HEALTHPACK:
Task->TaskType = TASK_GET_HEALTH;
break;
case DEPLOYABLE_ITEM_JETPACK:
case DEPLOYABLE_ITEM_HEAVYARMOUR:
Task->TaskType = TASK_GET_EQUIPMENT;
break;
default:
Task->TaskType = TASK_GET_WEAPON;
break;
}
Task->TaskTarget = Target;
Task->TaskLocation = PickupLocation;
Task->bTaskIsUrgent = bIsUrgent;
}
void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const bool bIsUrgent)
{
if (FNullEnt(Target) || (Target->v.deadflag != DEAD_NO))
@ -2940,7 +2996,7 @@ void AITASK_SetUseTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target
Task->TaskType = TASK_USE;
Task->TaskTarget = Target;
Task->TaskLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UseLocation, UTIL_MetresToGoldSrcUnits(10.0f));
Task->TaskLocation = UseLocation;
Task->bTaskIsUrgent = bIsUrgent;
Task->TaskLength = 10.0f;
Task->TaskStartedTime = gpGlobals->time;

View file

@ -66,6 +66,7 @@ void AITASK_SetReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task,
void AITASK_SetSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const Vector WaitLocation, bool bIsUrgent);
void AITASK_SetMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, bool bIsUrgent);
void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const bool bIsUrgent);
void AITASK_SetPickupTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target, const bool bIsUrgent);
void BotProgressTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task);

View file

@ -13,6 +13,9 @@
#include "../AvHMarineEquipmentConstants.h"
#include "../AvHServerUtil.h"
extern nav_mesh NavMeshes[MAX_NAV_MESHES]; // Array of nav meshes. Currently only 3 are used (building, onos, and regular)
extern nav_profile BaseNavProfiles[MAX_NAV_PROFILES]; // Array of nav profiles
int BotGetCurrentWeaponClipAmmo(const AvHAIPlayer* pBot)
{
AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast<AvHBasePlayerWeapon*>(pBot->Player->m_pActiveItem);

View file

@ -1424,11 +1424,16 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
if (!FNullEnt(TracedEntity))
{
const nav_door* Door = UTIL_GetNavDoorByEdict(TracedEntity);
nav_door* Door = UTIL_GetNavDoorByEdict(TracedEntity);
if (Door)
{
bool bThing = true;
DoorTrigger* Trigger = UTIL_GetNearestDoorTrigger(theAvHPlayer->pev->origin, Door, nullptr);
if (Trigger)
{
UTIL_DrawLine(INDEXENT(1), theAvHPlayer->pev->origin, UTIL_GetButtonFloorLocation(theAvHPlayer->pev->origin, Trigger->Edict), 10.0f);
}
}
}