Fixed bug with multiple off-mesh connections close together

This commit is contained in:
RGreenlees 2023-12-02 20:44:17 +00:00 committed by pierow
parent af54f6816b
commit f5ca613a4f
10 changed files with 227 additions and 260 deletions

View file

@ -61,7 +61,7 @@
/// @see dtNavMeshQuery
dtQueryFilter::dtQueryFilter() :
m_includeFlags(0xffffffff),
m_includeFlags(-1),
m_excludeFlags(0)
{
for (int i = 0; i < DT_MAX_AREAS; ++i)

View file

@ -94,16 +94,12 @@ dtTileCache::~dtTileCache()
}
dtFree(m_obstacles);
m_obstacles = 0;
dtFree(m_offMeshConnections);
m_offMeshConnections = 0;
dtFree(m_posLookup);
m_posLookup = 0;
dtFree(m_tiles);
m_tiles = 0;
m_nreqs = 0;
m_nOffMeshReqs = 0;
m_nupdate = 0;
@ -423,6 +419,8 @@ dtStatus dtTileCache::addOffMeshConnection(const float* spos, const float* epos,
memset(req, 0, sizeof(OffMeshRequest));
req->action = REQUEST_OFFMESH_ADD;
req->ref = getOffMeshRef(con);
con->userId = req->ref;
if (result)
*result = req->ref;

View file

@ -77,6 +77,33 @@ struct TileCacheSetExportHeader
int OffMeshConsOffset;
};
struct TileCacheBuildHeader
{
int magic;
int version;
int numRegularTiles;
int numOnosTiles;
int numBuildingTiles;
dtNavMeshParams regularMeshParams;
dtTileCacheParams regularCacheParams;
dtNavMeshParams onosMeshParams;
dtTileCacheParams onosCacheParams;
dtNavMeshParams buildingMeshParams;
dtTileCacheParams buildingCacheParams;
int NumSurfTypes;
int SurfTypesOffset;
int NumOffMeshCons;
int OffMeshConsOffset;
int NumConvexVols;
int ConvexVolOffset;
};
struct TileCacheTileHeader
{
dtCompressedTileRef tileRef;
@ -571,17 +598,15 @@ bool LoadNavMesh(const char* mapname)
FILE* savedFile = fopen(filename, "rb");
if (!savedFile)
{
char buf[64];
sprintf(buf, "Nav file for map %s not found.\n", mapname);
ALERT(at_console, buf);
return false;
}
if (!savedFile) { return false; }
LinearAllocator* m_talloc = new LinearAllocator(32000);
FastLZCompressor* m_tcomp = new FastLZCompressor;
MeshProcess* m_tmproc = new MeshProcess;
// Read header.
TileCacheSetExportHeader header;
size_t headerReadReturnCode = fread(&header, sizeof(TileCacheSetExportHeader), 1, savedFile);
TileCacheBuildHeader header;
size_t headerReadReturnCode = fread(&header, sizeof(TileCacheBuildHeader), 1, savedFile);
if (headerReadReturnCode != 1)
{
// Error or early EOF
@ -589,139 +614,53 @@ bool LoadNavMesh(const char* mapname)
UnloadNavigationData();
return false;
}
if (header.magic != TILECACHESET_MAGIC)
if (header.magic != TILECACHESET_MAGIC || header.version != TILECACHESET_VERSION)
{
char buf[64];
sprintf(buf, "Header Magic does not match! %d\n", header.magic);
ALERT(at_console, buf);
fclose(savedFile);
UnloadNavigationData();
return false;
}
if (header.version != TILECACHESET_VERSION)
{
ALERT(at_console, "Header version does not match!\n");
fclose(savedFile);
UnloadNavigationData();
return false;
}
NavMeshes[REGULAR_NAV_MESH].navMesh = dtAllocNavMesh();
if (!NavMeshes[REGULAR_NAV_MESH].navMesh)
dtNavMeshParams* NavMeshParams[3] = { &header.regularMeshParams, &header.onosMeshParams, &header.buildingMeshParams };
dtTileCacheParams* TileCacheParams[3] = { &header.regularCacheParams, &header.onosCacheParams, &header.buildingCacheParams };
for (int i = 0; i <= BUILDING_NAV_MESH; i++)
{
ALERT(at_console, "Could not allocate navmesh\n");
fclose(savedFile);
UnloadNavigationData();
return false;
NavMeshes[i].navMesh = dtAllocNavMesh();
if (!NavMeshes[i].navMesh)
{
fclose(savedFile);
UnloadNavigationData();
return false;
}
dtStatus status = NavMeshes[i].navMesh->init(NavMeshParams[i]);
if (dtStatusFailed(status))
{
fclose(savedFile);
UnloadNavigationData();
return false;
}
NavMeshes[i].tileCache = dtAllocTileCache();
if (!NavMeshes[i].tileCache)
{
fclose(savedFile);
UnloadNavigationData();
return false;
}
status = NavMeshes[i].tileCache->init(TileCacheParams[i], m_talloc, m_tcomp, m_tmproc);
if (dtStatusFailed(status))
{
ALERT(at_console, "Could not initialise tile cache\n");
fclose(savedFile);
UnloadNavigationData();
return false;
}
}
dtStatus status = NavMeshes[REGULAR_NAV_MESH].navMesh->init(&header.regularMeshParams);
if (dtStatusFailed(status))
{
ALERT(at_console, "Could not initialise nav mesh\n");
fclose(savedFile);
UnloadNavigationData();
return false;
}
NavMeshes[REGULAR_NAV_MESH].tileCache = dtAllocTileCache();
if (!NavMeshes[REGULAR_NAV_MESH].tileCache)
{
ALERT(at_console, "Could not allocate tile cache\n");
fclose(savedFile);
UnloadNavigationData();
return false;
}
NavMeshes[ONOS_NAV_MESH].navMesh = dtAllocNavMesh();
if (!NavMeshes[ONOS_NAV_MESH].navMesh)
{
ALERT(at_console, "Could not allocate onos navmesh\n");
fclose(savedFile);
UnloadNavigationData();
return false;
}
status = NavMeshes[ONOS_NAV_MESH].navMesh->init(&header.onosMeshParams);
if (dtStatusFailed(status))
{
ALERT(at_console, "Could not initialise onos nav mesh\n");
fclose(savedFile);
UnloadNavigationData();
return false;
}
NavMeshes[ONOS_NAV_MESH].tileCache = dtAllocTileCache();
if (!NavMeshes[ONOS_NAV_MESH].tileCache)
{
ALERT(at_console, "Could not allocate onos tile cache\n");
fclose(savedFile);
UnloadNavigationData();
return false;
}
NavMeshes[BUILDING_NAV_MESH].navMesh = dtAllocNavMesh();
if (!NavMeshes[BUILDING_NAV_MESH].navMesh)
{
ALERT(at_console, "Could not allocate building navmesh\n");
fclose(savedFile);
UnloadNavigationData();
return false;
}
status = NavMeshes[BUILDING_NAV_MESH].navMesh->init(&header.buildingMeshParams);
if (dtStatusFailed(status))
{
ALERT(at_console, "Could not initialise building nav mesh\n");
fclose(savedFile);
UnloadNavigationData();
return false;
}
NavMeshes[BUILDING_NAV_MESH].tileCache = dtAllocTileCache();
if (!NavMeshes[BUILDING_NAV_MESH].tileCache)
{
ALERT(at_console, "Could not allocate building tile cache\n");
fclose(savedFile);
UnloadNavigationData();
return false;
}
int CurrFilePos = ftell(savedFile);
LinearAllocator* m_talloc = new LinearAllocator(32000);
FastLZCompressor* m_tcomp = new FastLZCompressor;
MeshProcess* m_tmproc = new MeshProcess;
// TODO: Need to pass all off mesh connection verts, areas, flags etc as arrays to m_tmproc. Needs to be exported from recast as such
status = NavMeshes[REGULAR_NAV_MESH].tileCache->init(&header.regularCacheParams, m_talloc, m_tcomp, m_tmproc);
if (dtStatusFailed(status))
{
ALERT(at_console, "Could not initialise tile cache\n");
fclose(savedFile);
UnloadNavigationData();
return false;
}
status = NavMeshes[ONOS_NAV_MESH].tileCache->init(&header.onosCacheParams, m_talloc, m_tcomp, m_tmproc);
if (dtStatusFailed(status))
{
ALERT(at_console, "Could not initialise tile cache\n");
fclose(savedFile);
UnloadNavigationData();
return false;
}
status = NavMeshes[BUILDING_NAV_MESH].tileCache->init(&header.buildingCacheParams, m_talloc, m_tcomp, m_tmproc);
if (dtStatusFailed(status))
{
ALERT(at_console, "Could not initialise tile cache\n");
fclose(savedFile);
UnloadNavigationData();
return false;
}
fseek(savedFile, CurrFilePos, SEEK_SET);
// Read tiles.
for (int i = 0; i < header.numRegularTiles; ++i)
@ -851,43 +790,24 @@ bool LoadNavMesh(const char* mapname)
for (int ii = 0; ii < BUILDING_NAV_MESH; ii++)
{
NavMeshes[ii].tileCache->addOffMeshConnection(&def.pos[0], &def.pos[3], def.rad, def.area, def.flags, def.bBiDir, 0);
NavMeshes[ii].tileCache->addOffMeshConnection(&def.pos[0], &def.pos[3], 10.0f, def.area, def.flags, def.bBiDir, 0);
}
}
fclose(savedFile);
NavMeshes[REGULAR_NAV_MESH].navQuery = dtAllocNavMeshQuery();
dtStatus initStatus = NavMeshes[REGULAR_NAV_MESH].navQuery->init(NavMeshes[REGULAR_NAV_MESH].navMesh, 65535);
if (dtStatusFailed(initStatus))
for (int i = 0; i <= BUILDING_NAV_MESH; i++)
{
ALERT(at_console, "Could not initialise nav query\n");
UnloadNavigationData();
return false;
}
NavMeshes[i].navQuery = dtAllocNavMeshQuery();
NavMeshes[ONOS_NAV_MESH].navQuery = dtAllocNavMeshQuery();
dtStatus initStatus = NavMeshes[i].navQuery->init(NavMeshes[i].navMesh, 65535);
initStatus = NavMeshes[ONOS_NAV_MESH].navQuery->init(NavMeshes[ONOS_NAV_MESH].navMesh, 65535);
if (dtStatusFailed(initStatus))
{
ALERT(at_console, "Could not initialise onos nav query\n");
UnloadNavigationData();
return false;
}
NavMeshes[BUILDING_NAV_MESH].navQuery = dtAllocNavMeshQuery();
initStatus = NavMeshes[BUILDING_NAV_MESH].navQuery->init(NavMeshes[BUILDING_NAV_MESH].navMesh, 65535);
if (dtStatusFailed(initStatus))
{
ALERT(at_console, "Could not initialise building nav query\n");
UnloadNavigationData();
return false;
if (dtStatusFailed(initStatus))
{
ALERT(at_console, "Could not initialise nav query\n");
UnloadNavigationData();
return false;
}
}
return true;
@ -914,120 +834,85 @@ void UTIL_PopulateBaseNavProfiles()
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);
BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF);
BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_FLY | SAMPLE_POLYFLAGS_WALLCLIMB | SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.setExcludeFlags(0);
BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB);
BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH;
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].bFlyingProfile = false;
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_SKULK;
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);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_WALLCLIMB, 1.0f);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_DUCKJUMP);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE | SAMPLE_POLYFLAGS_TEAM2PHASEGATE | SAMPLE_POLYFLAGS_DUCKJUMP | SAMPLE_POLYFLAGS_WELD | SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters.setExcludeFlags(0);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH;
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].bFlyingProfile = false;
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_GORGE;
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);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.setExcludeFlags(0);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_DUCKJUMP);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_DUCKJUMP);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH;
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);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_WALLCLIMB, 1.0f);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.setExcludeFlags(0);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH;
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);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_WALLCLIMB, 1.0f);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.setExcludeFlags(0);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].NavMeshIndex = ONOS_NAV_MESH;
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);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.setExcludeFlags(0);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_NOONOS);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM1PHASEGATE);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_TEAM2PHASEGATE);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_WELD);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_NOONOS);
BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.removeIncludeFlags(SAMPLE_POLYFLAGS_FLY);
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].NavMeshIndex = BUILDING_NAV_MESH;
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF);
BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE].Filters.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
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.setIncludeFlags(SAMPLE_POLYFLAGS_ALL);
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;
}

View file

@ -63,7 +63,7 @@ enum SamplePolyFlags
SAMPLE_POLYFLAGS_TEAM2STRUCTURE = 1 << 12, // A team 2 structure is in the way that cannot be jumped over. Impassable to team 2 players (assume cannot teamkill own structures)
SAMPLE_POLYFLAGS_WELD = 1 << 13, // Requires a welder to get through here
SAMPLE_POLYFLAGS_DOOR = 1 << 14, // Requires a welder to get through here
SAMPLE_POLYFLAGS_LIFT = 1 << 15, // Disabled, not usable by anyone
SAMPLE_POLYFLAGS_LIFT = 1 << 15, // Requires using a lift or moving platform
SAMPLE_POLYFLAGS_DISABLED = 1 << 16, // Disabled, not usable by anyone
SAMPLE_POLYFLAGS_ALL = -1 // All abilities.

View file

@ -631,14 +631,23 @@ void AIMGR_ResetRound()
AIStartedTime = gpGlobals->time;
}
AITAC_ClearMapAIData();
UTIL_PopulateDoors();
UTIL_PopulateWeldableObstacles();
AITAC_ClearMapAIData();
ALERT(at_console, "AI Manager Reset Round\n");
}
void AIMGR_RoundStarted()
{
AITAC_RefreshHiveData();
UTIL_UpdateTileCache();
AITAC_RefreshResourceNodes();
}
void AIMGR_ClearBotData()
{
// We have to be careful here, depending on how the nav data is being unloaded, there could be stale references in the ActiveAIPlayers list.

View file

@ -15,6 +15,8 @@ void AIMGR_BotPrecache();
void AIMGR_ResetRound();
// Called when a new map is loaded. Clears all tactical information AND loads new navmesh.
void AIMGR_NewMap();
// Called when the match begins (countdown finished). Populates initial tactical information.
void AIMGR_RoundStarted();
// Adds a new AI player to a team (0 = Auto-assign, 1 = Team A, 2 = Team B)
void AIMGR_AddAIPlayerToTeam(int Team);

View file

@ -570,7 +570,7 @@ void AITAC_RefreshHiveData()
Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team)
{
if (TeamAStartingLocation == ZERO_VECTOR || TeamBStartingLocation == ZERO_VECTOR)
if (vIsZero(TeamAStartingLocation) || vIsZero(TeamBStartingLocation))
{
AvHTeam* AvHTeamARef = GetGameRules()->GetTeamA();
AvHTeam* AvHTeamBRef = GetGameRules()->GetTeamB();
@ -606,13 +606,13 @@ Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team)
if (AvHTeamBRef->GetTeamType() == AVH_CLASS_TYPE_MARINE)
{
TeamBStartingLocation = AvHTeamBRef->GetStartingLocation();
TeamBStartingLocation = TeamStartLocation;
}
else
{
TeamBStartingLocation = TeamStartLocation;
const AvHAIHiveDefinition* Hive = AITAC_GetHiveNearestLocation(TeamStartLocation);
const AvHAIHiveDefinition* Hive = AITAC_GetActiveHiveNearestLocation(TeamStartLocation);
if (Hive)
{
@ -730,14 +730,29 @@ void AITAC_RefreshReachabilityForItem(AvHAIDroppedItem* Item)
}
}
void AITAC_RefreshAllResNodeReachability()
{
for (auto it = ResourceNodes.begin(); it != ResourceNodes.end(); it++)
{
AITAC_RefreshReachabilityForResNode(&(*it));
}
}
void AITAC_RefreshReachabilityForResNode(AvHAIResourceNode* ResNode)
{
if (Hives.size() == 0)
{
AITAC_RefreshHiveData();
}
ResNode->bReachabilityMarkedDirty = false;
ResNode->TeamAReachabilityFlags = AI_REACHABILITY_NONE;
ResNode->TeamBReachabilityFlags = AI_REACHABILITY_NONE;
bool bOnNavMesh = UTIL_PointIsOnNavmesh(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], ResNode->Location, Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach));
Vector ResNodeLocation = AdjustPointForPathfinding(ResNode->Location);
bool bOnNavMesh = UTIL_PointIsOnNavmesh(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], ResNodeLocation, Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach));
if (!bOnNavMesh)
{
@ -748,7 +763,7 @@ void AITAC_RefreshReachabilityForResNode(AvHAIResourceNode* ResNode)
if (GetGameRules()->GetTeamA()->GetTeamType() == AVH_CLASS_TYPE_MARINE)
{
bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNodeLocation, max_player_use_reach);
if (bIsReachableMarine)
{
@ -762,7 +777,7 @@ void AITAC_RefreshReachabilityForResNode(AvHAIResourceNode* ResNode)
WelderProfile.Filters.removeExcludeFlags(SAMPLE_POLYFLAGS_WELD);
bool bIsReachableWelder = UTIL_PointIsReachable(WelderProfile, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableWelder = UTIL_PointIsReachable(WelderProfile, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNodeLocation, max_player_use_reach);
if (bIsReachableWelder)
{
@ -772,9 +787,9 @@ void AITAC_RefreshReachabilityForResNode(AvHAIResourceNode* ResNode)
}
else
{
bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableGorge = UTIL_PointIsReachable(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNodeLocation, max_player_use_reach);
bool bIsReachableGorge = UTIL_PointIsReachable(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNodeLocation, max_player_use_reach);
bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNodeLocation, max_player_use_reach);
if (bIsReachableSkulk)
{
@ -794,7 +809,7 @@ void AITAC_RefreshReachabilityForResNode(AvHAIResourceNode* ResNode)
if (GetGameRules()->GetTeamB()->GetTeamType() == AVH_CLASS_TYPE_MARINE)
{
bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), ResNodeLocation, max_player_use_reach);
if (bIsReachableMarine)
{
@ -808,7 +823,7 @@ void AITAC_RefreshReachabilityForResNode(AvHAIResourceNode* ResNode)
WelderProfile.Filters.removeExcludeFlags(SAMPLE_POLYFLAGS_WELD);
bool bIsReachableWelder = UTIL_PointIsReachable(WelderProfile, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableWelder = UTIL_PointIsReachable(WelderProfile, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), ResNodeLocation, max_player_use_reach);
if (bIsReachableWelder)
{
@ -818,9 +833,16 @@ void AITAC_RefreshReachabilityForResNode(AvHAIResourceNode* ResNode)
}
else
{
bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableGorge = UTIL_PointIsReachable(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), ResNodeLocation, max_player_use_reach);
if (!bIsReachableSkulk)
{
UTIL_DrawLine(INDEXENT(1), INDEXENT(1)->v.origin, ResNodeLocation, 20.0f);
UTIL_DrawLine(INDEXENT(1), INDEXENT(1)->v.origin, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), 20.0f, 255, 255, 0);
}
bool bIsReachableGorge = UTIL_PointIsReachable(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), ResNodeLocation, max_player_use_reach);
bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), ResNodeLocation, max_player_use_reach);
if (bIsReachableSkulk)
{
@ -923,6 +945,12 @@ AvHAIResourceNode* AITAC_GetRandomResourceNode(AvHTeamNumber SearchingTeam, cons
void AITAC_UpdateMapAIData()
{
AITAC_RefreshHiveData();
UTIL_UpdateDoors(false);
UTIL_UpdateWeldableObstacles();
if (gpGlobals->time - last_structure_refresh_time >= structure_inventory_refresh_rate)
{
AITAC_RefreshBuildableStructures();
@ -935,11 +963,6 @@ void AITAC_UpdateMapAIData()
AITAC_RefreshMarineItems();
last_item_refresh_time = gpGlobals->time;
}
UTIL_UpdateDoors(false);
UTIL_UpdateWeldableObstacles();
AITAC_RefreshHiveData();
}
void AITAC_CheckNavMeshModified()
@ -1298,6 +1321,11 @@ void AITAC_OnItemDropped(const AvHAIDroppedItem* NewItem)
void AITAC_RefreshReachabilityForStructure(AvHAIBuildableStructure* Structure)
{
if (Hives.size() == 0)
{
AITAC_RefreshHiveData();
}
Structure->bReachabilityMarkedDirty = false;
bool bIsOnNavMesh = UTIL_PointIsOnNavmesh(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], UTIL_GetEntityGroundLocation(Structure->edict), Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach));
@ -1612,11 +1640,9 @@ void AITAC_OnStructureDestroyed(AvHAIBuildableStructure* DestroyedStructure)
if (DestroyedStructure->StructureType == STRUCTURE_MARINE_PHASEGATE)
{
// Eliminate all connections from this phase gate
for (auto it = DestroyedStructure->OffMeshConnections.begin(); it != DestroyedStructure->OffMeshConnections.begin();)
for (auto it = DestroyedStructure->OffMeshConnections.begin(); it != DestroyedStructure->OffMeshConnections.end(); it++)
{
UTIL_RemoveOffMeshConnections(&(*it));
it = DestroyedStructure->OffMeshConnections.erase(it);
}
DestroyedStructure->OffMeshConnections.clear();
@ -2024,6 +2050,27 @@ const AvHAIHiveDefinition* AITAC_GetHiveNearestLocation(const Vector SearchLocat
return Result;
}
const AvHAIHiveDefinition* AITAC_GetActiveHiveNearestLocation(const Vector SearchLocation)
{
AvHAIHiveDefinition* Result = nullptr;
float MinDist = 0.0f;
for (auto it = Hives.begin(); it != Hives.end(); it++)
{
if (it->Status != HIVE_STATUS_BUILT) { continue; }
float ThisDist = vDist3DSq(SearchLocation, it->Location);
if (!Result || ThisDist < MinDist)
{
Result = &(*it);
MinDist = ThisDist;
}
}
return Result;
}
AvHAIResourceNode* AITAC_GetNearestResourceNodeToLocation(const Vector Location)
{
AvHAIResourceNode* Result = nullptr;

View file

@ -34,6 +34,7 @@ void AITAC_RefreshBuildableStructures();
void AITAC_UpdateBuildableStructure(CBaseEntity* Structure);
void AITAC_RefreshReachabilityForStructure(AvHAIBuildableStructure* Structure);
void AITAC_RefreshReachabilityForResNode(AvHAIResourceNode* ResNode);
void AITAC_RefreshAllResNodeReachability();
void AITAC_RefreshReachabilityForItem(AvHAIDroppedItem* Item);
void AITAC_OnStructureCreated(AvHAIBuildableStructure* NewStructure);
void AITAC_OnStructureCompleted(AvHAIBuildableStructure* NewStructure);
@ -46,6 +47,7 @@ float AITAC_GetPhaseDistanceBetweenPoints(const Vector StartPoint, const Ve
const AvHAIHiveDefinition* AITAC_GetHiveAtIndex(int Index);
const AvHAIHiveDefinition* AITAC_GetHiveNearestLocation(const Vector SearchLocation);
const AvHAIHiveDefinition* AITAC_GetActiveHiveNearestLocation(const Vector SearchLocation);
Vector AITAC_GetCommChairLocation(AvHTeamNumber Team);
edict_t* AITAC_GetCommChair(AvHTeamNumber Team);

View file

@ -1485,6 +1485,29 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
theSuccess = true;
}
else if (FStrEq(pcmd, "testreachable"))
{
Vector TeamAStart = AITAC_GetTeamStartingLocation(TEAM_ONE);
Vector TeamBStart = AITAC_GetTeamStartingLocation(TEAM_TWO);
Vector CheckLoc = UTIL_GetFloorUnderEntity(theAvHPlayer->edict());
UTIL_DrawLine(INDEXENT(1), TeamAStart, CheckLoc, 10.0f, 0, 0, 255);
UTIL_DrawLine(INDEXENT(1), TeamBStart, CheckLoc, 10.0f, 255, 255, 0);
bool bTeamARechable = UTIL_PointIsReachable(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), TeamAStart, CheckLoc, max_player_use_reach);
bool bTeamBRechable = UTIL_PointIsReachable(GetBaseNavProfile(SKULK_BASE_NAV_PROFILE), TeamBStart, CheckLoc, max_player_use_reach);
char buf[64];
sprintf(buf, "Team A: %s\n", (bTeamARechable) ? "True" : "False");
UTIL_SayText(buf, theAvHPlayer);
sprintf(buf, "Team B: %s\n", (bTeamBRechable) ? "True" : "False");
UTIL_SayText(buf, theAvHPlayer);
theSuccess = true;
}
else if (FStrEq(pcmd, "tracelift"))
{
Vector TraceStart = GetPlayerEyePosition(theAvHPlayer->edict()); // origin + pev->view_ofs

View file

@ -3417,6 +3417,7 @@ void AvHGamerules::SetGameStarted(bool inGameStarted)
if(!this->mGameStarted && inGameStarted)
{
FireTargets(ktGameStartedStatus, NULL, NULL, USE_TOGGLE, 0.0f);
AIMGR_RoundStarted();
//AvHNexus::startGame();
}
this->mGameStarted = inGameStarted;