From b7db5adcaabaa9fec77e2cfdeee896baec7d485b Mon Sep 17 00:00:00 2001 From: RGreenlees Date: Sat, 14 Oct 2023 20:54:42 +0100 Subject: [PATCH] Reworked nav profiles Nav profiles for bots are now dynamically updated to take into account changing capabilities, such as picking up a welder --- main/source/mod/AIPlayers/AvHAIConstants.h | 20 +- main/source/mod/AIPlayers/AvHAIHelper.cpp | 119 ++ main/source/mod/AIPlayers/AvHAIHelper.h | 9 + main/source/mod/AIPlayers/AvHAINavigation.cpp | 1700 +++++++++-------- main/source/mod/AIPlayers/AvHAINavigation.h | 167 +- main/source/mod/AIPlayers/AvHAIPlayer.cpp | 40 +- main/source/mod/AIPlayers/AvHAIPlayer.h | 5 + .../mod/AIPlayers/AvHAIPlayerManager.cpp | 47 +- .../source/mod/AIPlayers/AvHAIPlayerManager.h | 1 + main/source/mod/AIPlayers/AvHAIPlayerUtil.cpp | 27 +- main/source/mod/AIPlayers/AvHAIPlayerUtil.h | 2 + main/source/mod/AIPlayers/AvHAITactical.cpp | 42 +- main/source/mod/AIPlayers/AvHAITactical.h | 2 +- main/source/mod/AIPlayers/AvHAITask.cpp | 83 +- .../mod/AIPlayers/AvHAIWeaponHelper.cpp | 34 +- 15 files changed, 1232 insertions(+), 1066 deletions(-) diff --git a/main/source/mod/AIPlayers/AvHAIConstants.h b/main/source/mod/AIPlayers/AvHAIConstants.h index 949fea97..55517147 100644 --- a/main/source/mod/AIPlayers/AvHAIConstants.h +++ b/main/source/mod/AIPlayers/AvHAIConstants.h @@ -3,6 +3,9 @@ #ifndef AVH_AI_CONSTANTS_H #define AVH_AI_CONSTANTS_H +#include "DetourStatus.h" +#include "DetourNavMeshQuery.h" + #include "../AvHHive.h" #include "../AvHEntities.h" @@ -98,7 +101,8 @@ typedef enum _AI_REACHABILITY_STATUS AI_REACHABILITY_NONE = 0, AI_REACHABILITY_MARINE = 1u << 0, AI_REACHABILITY_SKULK = 1u << 1, - AI_REACHABILITY_ONOS = 1u << 2 + AI_REACHABILITY_ONOS = 1u << 2, + AI_REACHABILITY_WELDER = 1u << 3, } AvHAIReachabilityStatus; // Data structure used to track resource nodes in the map @@ -189,6 +193,15 @@ typedef enum _STRUCTUREPURPOSE } StructurePurpose; +// A nav profile combines a nav mesh reference (indexed into NavMeshes) and filters to determine how a bot should find paths +typedef struct _NAV_PROFILE +{ + int NavMeshIndex = -1; + dtQueryFilter Filters; + bool bFlyingProfile = false; + AvHAIReachabilityStatus ReachabilityFlag = AI_REACHABILITY_NONE; +} nav_profile; + typedef struct _DEPLOYABLE_SEARCH_FILTER { unsigned int DeployableTypes = SEARCH_ALL_STRUCTURES; @@ -434,7 +447,6 @@ typedef struct _NAV_STATUS BotMoveStyle MoveStyle = MOVESTYLE_NORMAL; // Current desired move style (e.g. normal, ambush, hide). Will trigger new path calculations if this changes float LastPathCalcTime = 0.0f; // When the bot last calculated a path, to limit how frequently it can recalculate - int LastMoveProfile = -1; // The last navigation profile used by the bot. Will trigger new path calculations if this changes (e.g. changed class, changed move style) bool bPendingRecalculation = false; // This bot should recalculate its path as soon as it can @@ -443,6 +455,9 @@ typedef struct _NAV_STATUS AvHAIPlayerTask MovementTask; + nav_profile NavProfile; + bool bNavProfileChanged = false; + } nav_status; // Type of goal the commander wants to achieve @@ -506,6 +521,7 @@ typedef struct AVH_AI_PLAYER byte AdjustedMsec = 0; bool bIsPendingKill = false; + bool bIsInactive = false; float LastUseTime = 0.0f; diff --git a/main/source/mod/AIPlayers/AvHAIHelper.cpp b/main/source/mod/AIPlayers/AvHAIHelper.cpp index ef8cd156..d49714ff 100644 --- a/main/source/mod/AIPlayers/AvHAIHelper.cpp +++ b/main/source/mod/AIPlayers/AvHAIHelper.cpp @@ -5,6 +5,8 @@ #include "../AvHGamerules.h" +int m_spriteTexture; + bool UTIL_CommanderTrace(const edict_t* pEdict, const Vector& start, const Vector& end) { TraceResult hit; @@ -239,4 +241,121 @@ bool GetNearestMapLocationAtPoint(vec3_t SearchLocation, string& outLocation) } return theSuccess; +} + +void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end) +{ + if (FNullEnt(pEntity) || pEntity->free) { return; } + + MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity); + WRITE_BYTE(TE_BEAMPOINTS); + WRITE_COORD(start.x); + WRITE_COORD(start.y); + WRITE_COORD(start.z); + WRITE_COORD(end.x); + WRITE_COORD(end.y); + WRITE_COORD(end.z); + WRITE_SHORT(m_spriteTexture); + WRITE_BYTE(1); // framestart + WRITE_BYTE(10); // framerate + WRITE_BYTE(1); // life in 0.1's + WRITE_BYTE(5); // width + WRITE_BYTE(0); // noise + + WRITE_BYTE(255); // r, g, b + WRITE_BYTE(255); // r, g, b + WRITE_BYTE(255); // r, g, b + + WRITE_BYTE(250); // brightness + WRITE_BYTE(5); // speed + MESSAGE_END(); +} + +void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSeconds) +{ + if (FNullEnt(pEntity) || pEntity->free) { return; } + + int timeTenthSeconds = (int)floorf(drawTimeSeconds * 10.0f); + timeTenthSeconds = fmaxf(timeTenthSeconds, 1); + + MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity); + WRITE_BYTE(TE_BEAMPOINTS); + WRITE_COORD(start.x); + WRITE_COORD(start.y); + WRITE_COORD(start.z); + WRITE_COORD(end.x); + WRITE_COORD(end.y); + WRITE_COORD(end.z); + WRITE_SHORT(m_spriteTexture); + WRITE_BYTE(1); // framestart + WRITE_BYTE(10); // framerate + WRITE_BYTE(timeTenthSeconds); // life in 0.1's + WRITE_BYTE(5); // width + WRITE_BYTE(0); // noise + + WRITE_BYTE(255); // r, g, b + WRITE_BYTE(255); // r, g, b + WRITE_BYTE(255); // r, g, b + + WRITE_BYTE(250); // brightness + WRITE_BYTE(5); // speed + MESSAGE_END(); +} + +void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSeconds, int r, int g, int b) +{ + if (FNullEnt(pEntity) || pEntity->free) { return; } + + int timeTenthSeconds = (int)floorf(drawTimeSeconds * 10.0f); + + MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity); + WRITE_BYTE(TE_BEAMPOINTS); + WRITE_COORD(start.x); + WRITE_COORD(start.y); + WRITE_COORD(start.z); + WRITE_COORD(end.x); + WRITE_COORD(end.y); + WRITE_COORD(end.z); + WRITE_SHORT(m_spriteTexture); + WRITE_BYTE(1); // framestart + WRITE_BYTE(10); // framerate + WRITE_BYTE(timeTenthSeconds); // life in 0.1's + WRITE_BYTE(5); // width + WRITE_BYTE(0); // noise + + WRITE_BYTE(r); // r, g, b + WRITE_BYTE(g); // r, g, b + WRITE_BYTE(b); // r, g, b + + WRITE_BYTE(250); // brightness + WRITE_BYTE(5); // speed + MESSAGE_END(); +} + +void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, int r, int g, int b) +{ + if (FNullEnt(pEntity) || pEntity->free) { return; } + + MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity); + WRITE_BYTE(TE_BEAMPOINTS); + WRITE_COORD(start.x); + WRITE_COORD(start.y); + WRITE_COORD(start.z); + WRITE_COORD(end.x); + WRITE_COORD(end.y); + WRITE_COORD(end.z); + WRITE_SHORT(m_spriteTexture); + WRITE_BYTE(1); // framestart + WRITE_BYTE(10); // framerate + WRITE_BYTE(1); // life in 0.1's + WRITE_BYTE(5); // width + WRITE_BYTE(0); // noise + + WRITE_BYTE(r); // r, g, b + WRITE_BYTE(g); // r, g, b + WRITE_BYTE(b); // r, g, b + + WRITE_BYTE(250); // brightness + WRITE_BYTE(5); // speed + MESSAGE_END(); } \ No newline at end of file diff --git a/main/source/mod/AIPlayers/AvHAIHelper.h b/main/source/mod/AIPlayers/AvHAIHelper.h index 5c9d1f37..56fe1972 100644 --- a/main/source/mod/AIPlayers/AvHAIHelper.h +++ b/main/source/mod/AIPlayers/AvHAIHelper.h @@ -30,4 +30,13 @@ bool GetNearestMapLocationAtPoint(vec3_t SearchLocation, string& outLocation); AvHAIDeployableStructureType GetDeployableObjectTypeFromEdict(const edict_t* StructureEdict); +// 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 +void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSeconds); +// Draws a coloured line using RGB input, between start and end for the given player (pEntity) for 0.1s +void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, int r, int g, int b); +// Draws a coloured line using RGB input, between start and end for the given player (pEntity) for given number of seconds +void UTIL_DrawLine(edict_t* pEntity, Vector start, Vector end, float drawTimeSeconds, int r, int g, int b); + #endif \ No newline at end of file diff --git a/main/source/mod/AIPlayers/AvHAINavigation.cpp b/main/source/mod/AIPlayers/AvHAINavigation.cpp index 23058b64..a09e0ffd 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.cpp +++ b/main/source/mod/AIPlayers/AvHAINavigation.cpp @@ -244,35 +244,35 @@ struct MeshProcess : public dtTileCacheMeshProcess polyAreas[i] = SAMPLE_POLYAREA_GROUND; polyFlags[i] = SAMPLE_POLYFLAGS_WALK; } - else if (polyAreas[i] == DT_TILECACHE_CLIMBABLE_AREA) - { - polyAreas[i] = SAMPLE_POLYAREA_WALLCLIMB; - polyFlags[i] = SAMPLE_POLYFLAGS_WALLCLIMB; - } - else if (polyAreas[i] == DT_TILECACHE_LADDER_AREA) - { - polyAreas[i] = SAMPLE_POLYAREA_LADDER; - polyFlags[i] = SAMPLE_POLYFLAGS_LADDER; - } else if (polyAreas[i] == DT_TILECACHE_CROUCH_AREA) { polyAreas[i] = SAMPLE_POLYAREA_CROUCH; polyFlags[i] = SAMPLE_POLYFLAGS_WALK; } + else if (polyAreas[i] == DT_TILECACHE_WALLCLIMB_AREA) + { + polyAreas[i] = SAMPLE_POLYAREA_GROUND; + polyFlags[i] = SAMPLE_POLYFLAGS_WALLCLIMB; + } + else if (polyAreas[i] == DT_TILECACHE_LADDER_AREA) + { + polyAreas[i] = SAMPLE_POLYAREA_GROUND; + polyFlags[i] = SAMPLE_POLYFLAGS_LADDER; + } else if (polyAreas[i] == DT_TILECACHE_BLOCKED_AREA) { polyAreas[i] = SAMPLE_POLYAREA_BLOCKED; polyFlags[i] = SAMPLE_POLYFLAGS_BLOCKED; } - else if (polyAreas[i] == DT_TILECACHE_ASTRUCTURE_AREA) + else if (polyAreas[i] == DT_TILECACHE_TEAM1STRUCTURE_AREA) { - polyAreas[i] = SAMPLE_POLYAREA_ASTRUCTURE; - polyFlags[i] = SAMPLE_POLYFLAGS_ASTRUCTURE; + polyAreas[i] = SAMPLE_POLYAREA_BLOCKED; + polyFlags[i] = SAMPLE_POLYFLAGS_BLOCKED | SAMPLE_POLYFLAGS_TEAM1STRUCTURE; } - else if (polyAreas[i] == DT_TILECACHE_MSTRUCTURE_AREA) + else if (polyAreas[i] == DT_TILECACHE_TEAM2STRUCTURE_AREA) { - polyAreas[i] = SAMPLE_POLYAREA_MSTRUCTURE; - polyFlags[i] = SAMPLE_POLYFLAGS_MSTRUCTURE; + polyAreas[i] = SAMPLE_POLYAREA_BLOCKED; + polyFlags[i] = SAMPLE_POLYFLAGS_BLOCKED | SAMPLE_POLYFLAGS_TEAM2STRUCTURE; } else if (polyAreas[i] == DT_TILECACHE_WELD_AREA) { @@ -306,8 +306,8 @@ void UTIL_UpdateTileCache() Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDistanceFromWall) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(SKULK_REGULAR_NAV_PROFILE); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(SKULK_REGULAR_NAV_PROFILE); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(BaseNavProfiles[SKULK_BASE_NAV_PROFILE]); + const dtQueryFilter* m_navFilter = &BaseNavProfiles[SKULK_BASE_NAV_PROFILE].Filters; float Pos[3] = { Location.x, Location.z, -Location.y }; @@ -331,7 +331,7 @@ Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDis float AdjustLoc[3] = { AdjustLocation.x, AdjustLocation.z, -AdjustLocation.y }; - if (UTIL_TraceNav(SKULK_REGULAR_NAV_PROFILE, Location, AdjustLocation, 0.1f)) + if (UTIL_TraceNav(BaseNavProfiles[ALL_NAV_PROFILE], Location, AdjustLocation, 0.1f)) { return AdjustLocation; } @@ -346,12 +346,8 @@ Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDis Vector UTIL_GetNearestPointOnNavWall(AvHAIPlayer* pBot, const float MaxRadius) { - int NavProfileIndex = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - - if (NavProfileIndex < 0) { return g_vecZero; } - - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(pBot->BotNavInfo.NavProfile); + const dtQueryFilter* m_navFilter = &pBot->BotNavInfo.NavProfile.Filters; Vector Location = pBot->CurrentFloorPosition; @@ -372,20 +368,16 @@ Vector UTIL_GetNearestPointOnNavWall(AvHAIPlayer* pBot, const float MaxRadius) return g_vecZero; } -Vector UTIL_GetNearestPointOnNavWall(const int NavProfileIndex, const Vector Location, const float MaxRadius) +Vector UTIL_GetNearestPointOnNavWall(const nav_profile &NavProfile, const Vector Location, const float MaxRadius) { - if (NavProfileIndex < 0) - { - return g_vecZero; - } - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); + const dtQueryFilter* m_navFilter = &NavProfile.Filters; // Invalid nav profile if (!m_navQuery) { return g_vecZero; } - dtPolyRef StartPoly = UTIL_GetNearestPolyRefForLocation(NavProfileIndex, Location); + dtPolyRef StartPoly = UTIL_GetNearestPolyRefForLocation(NavProfile, Location); // Not on the nav mesh if (StartPoly == 0) { return Location; } @@ -542,7 +534,7 @@ void UnloadNavigationData() UTIL_ClearDoorData(); - memset(NavProfiles, 0, sizeof(nav_profile)); + memset(BaseNavProfiles, 0, sizeof(nav_profile)); memset(NavWeldableObstacles, 0, sizeof(NavWeldableObstacles)); NumWeldableObstacles = 0; @@ -888,6 +880,101 @@ bool LoadNavMesh(const char* mapname) return true; } +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_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.setExcludeFlags(0); + BaseNavProfiles[MARINE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB); + + 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_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_PHASEGATE); + 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_LADDER); + + BaseNavProfiles[GORGE_BASE_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH; + 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_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.setExcludeFlags(0); + BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB); + BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_PHASEGATE); + BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_DUCKJUMP); + BaseNavProfiles[GORGE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD); + + 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_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.setExcludeFlags(0); + BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_PHASEGATE); + BaseNavProfiles[LERK_BASE_NAV_PROFILE].Filters.addExcludeFlags(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_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.setExcludeFlags(0); + BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_PHASEGATE); + BaseNavProfiles[FADE_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD); + + 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_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.setExcludeFlags(0); + BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB); + BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_PHASEGATE); + BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD); + BaseNavProfiles[ONOS_BASE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_NOONOS); + + 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].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].bFlyingProfile = false; + BaseNavProfiles[ALL_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_SKULK; +} + bool loadNavigationData(const char* mapname) { @@ -898,203 +985,7 @@ bool loadNavigationData(const char* mapname) return false; } - NavProfiles[MARINE_REGULAR_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH; - NavProfiles[MARINE_REGULAR_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF); - NavProfiles[MARINE_REGULAR_NAV_PROFILE].Filters.setExcludeFlags(0); - NavProfiles[MARINE_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB); - NavProfiles[MARINE_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_MSTRUCTURE); - NavProfiles[MARINE_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD); - NavProfiles[MARINE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f); - NavProfiles[MARINE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_PHASEGATE, 0.1f); - NavProfiles[MARINE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_JUMP, 1.5f); - NavProfiles[MARINE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 2.0f); - NavProfiles[MARINE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALL, 1.0f); - NavProfiles[MARINE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LADDER, 1.0f); - NavProfiles[MARINE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHFALL, 10.0f); - NavProfiles[MARINE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHJUMP, 10.0f); - NavProfiles[MARINE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 2.0f); - NavProfiles[MARINE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_ASTRUCTURE, 20.0f); - NavProfiles[MARINE_REGULAR_NAV_PROFILE].bFlyingProfile = false; - NavProfiles[MARINE_REGULAR_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_MARINE; - - NavProfiles[MARINE_WELD_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH; - NavProfiles[MARINE_WELD_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF); - NavProfiles[MARINE_WELD_NAV_PROFILE].Filters.setExcludeFlags(0); - NavProfiles[MARINE_WELD_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB); - NavProfiles[MARINE_WELD_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_MSTRUCTURE); - NavProfiles[MARINE_WELD_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f); - NavProfiles[MARINE_WELD_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_PHASEGATE, 0.1f); - NavProfiles[MARINE_WELD_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_JUMP, 1.5f); - NavProfiles[MARINE_WELD_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 2.0f); - NavProfiles[MARINE_WELD_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALL, 1.0f); - NavProfiles[MARINE_WELD_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LADDER, 1.0f); - NavProfiles[MARINE_WELD_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHFALL, 10.0f); - NavProfiles[MARINE_WELD_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHJUMP, 10.0f); - NavProfiles[MARINE_WELD_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 2.0f); - NavProfiles[MARINE_WELD_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_ASTRUCTURE, 20.0f); - NavProfiles[MARINE_WELD_NAV_PROFILE].bFlyingProfile = false; - NavProfiles[MARINE_WELD_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_MARINE; - - NavProfiles[SKULK_REGULAR_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH; - NavProfiles[SKULK_REGULAR_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF); - NavProfiles[SKULK_REGULAR_NAV_PROFILE].Filters.setExcludeFlags(0); - NavProfiles[SKULK_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_LADDER); - NavProfiles[SKULK_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_ASTRUCTURE); - NavProfiles[SKULK_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_PHASEGATE); - NavProfiles[SKULK_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD); - NavProfiles[SKULK_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f); - NavProfiles[SKULK_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_JUMP, 1.5f); - NavProfiles[SKULK_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALL, 1.0f); - NavProfiles[SKULK_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_WALLCLIMB, 1.0f); - NavProfiles[SKULK_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHFALL, 1.0f); - NavProfiles[SKULK_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHJUMP, 1.0f); - NavProfiles[SKULK_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f); - NavProfiles[SKULK_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 2.0f); - NavProfiles[SKULK_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_MSTRUCTURE, 20.0f); - NavProfiles[SKULK_REGULAR_NAV_PROFILE].bFlyingProfile = false; - NavProfiles[SKULK_REGULAR_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_SKULK; - - NavProfiles[FADE_REGULAR_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH; - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF); - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.setExcludeFlags(0); - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_ASTRUCTURE); - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_PHASEGATE); - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD); - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f); - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_PHASEGATE, 0.1f); - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_JUMP, 1.5f); - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALL, 1.0f); - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LADDER, 2.0f); - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHFALL, 1.0f); - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHJUMP, 1.0f); - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 2.0f); - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_WALLCLIMB, 1.0f); - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 2.0f); - NavProfiles[FADE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_MSTRUCTURE, 20.0f); - NavProfiles[FADE_REGULAR_NAV_PROFILE].bFlyingProfile = false; - NavProfiles[FADE_REGULAR_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_SKULK; - - NavProfiles[GORGE_REGULAR_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH; - NavProfiles[GORGE_REGULAR_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF); - NavProfiles[GORGE_REGULAR_NAV_PROFILE].Filters.setExcludeFlags(0); - NavProfiles[GORGE_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB); - NavProfiles[GORGE_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_ASTRUCTURE); - NavProfiles[GORGE_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_PHASEGATE); - NavProfiles[GORGE_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD); - NavProfiles[GORGE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f); - NavProfiles[GORGE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_JUMP, 1.5f); - NavProfiles[GORGE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALL, 1.0f); - NavProfiles[GORGE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LADDER, 1.0f); - NavProfiles[GORGE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHFALL, 10.0f); - NavProfiles[GORGE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHJUMP, 10.0f); - NavProfiles[GORGE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f); - NavProfiles[GORGE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 2.0f); - NavProfiles[GORGE_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_MSTRUCTURE, 20.0f); - NavProfiles[GORGE_REGULAR_NAV_PROFILE].bFlyingProfile = false; - NavProfiles[GORGE_REGULAR_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_MARINE; - - NavProfiles[ONOS_REGULAR_NAV_PROFILE].NavMeshIndex = ONOS_NAV_MESH; - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.setExcludeFlags(0); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_ASTRUCTURE); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_PHASEGATE); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_NOONOS); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_JUMP, 3.0f); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALL, 1.0f); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LADDER, 1.0f); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHFALL, 10.0f); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHJUMP, 10.0f); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 3.0f); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 2.0f); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_MSTRUCTURE, 10.0f); - NavProfiles[ONOS_REGULAR_NAV_PROFILE].bFlyingProfile = false; - NavProfiles[ONOS_REGULAR_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_ONOS; - - NavProfiles[BUILDING_REGULAR_NAV_PROFILE].NavMeshIndex = BUILDING_NAV_MESH; - NavProfiles[BUILDING_REGULAR_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF); - NavProfiles[BUILDING_REGULAR_NAV_PROFILE].Filters.setExcludeFlags(0); - NavProfiles[BUILDING_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_BLOCKED); - NavProfiles[BUILDING_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_ASTRUCTURE); - NavProfiles[BUILDING_REGULAR_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_MSTRUCTURE); - NavProfiles[BUILDING_REGULAR_NAV_PROFILE].bFlyingProfile = false; - NavProfiles[BUILDING_REGULAR_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_MARINE; - - NavProfiles[GORGE_BUILD_NAV_PROFILE].NavMeshIndex = BUILDING_NAV_MESH; - NavProfiles[GORGE_BUILD_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF); - NavProfiles[GORGE_BUILD_NAV_PROFILE].Filters.setExcludeFlags(0); - NavProfiles[GORGE_BUILD_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_BLOCKED); - NavProfiles[GORGE_BUILD_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_ASTRUCTURE); - NavProfiles[GORGE_BUILD_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_MSTRUCTURE); - NavProfiles[GORGE_BUILD_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB); - NavProfiles[GORGE_BUILD_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_PHASEGATE); - NavProfiles[GORGE_BUILD_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD); - NavProfiles[GORGE_BUILD_NAV_PROFILE].bFlyingProfile = false; - NavProfiles[GORGE_BUILD_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_MARINE; - - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH; - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF); - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].Filters.setExcludeFlags(0); - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_LADDER); - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_ASTRUCTURE); - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_PHASEGATE); - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD); - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 50.0f); - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_JUMP, 1.0f); - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALL, 1.0f); - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_WALLCLIMB, 1.0f); - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHFALL, 1.0f); - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHJUMP, 1.0f); - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f); - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 2.0f); - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_MSTRUCTURE, 20.0f); - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].bFlyingProfile = false; - NavProfiles[SKULK_AMBUSH_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_SKULK; - - NavProfiles[GORGE_HIDE_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH; - NavProfiles[GORGE_HIDE_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF); - NavProfiles[GORGE_HIDE_NAV_PROFILE].Filters.setExcludeFlags(0); - NavProfiles[GORGE_HIDE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WALLCLIMB); - NavProfiles[GORGE_HIDE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_ASTRUCTURE); - NavProfiles[GORGE_HIDE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_PHASEGATE); - NavProfiles[GORGE_HIDE_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD); - NavProfiles[GORGE_HIDE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 5.0f); - NavProfiles[GORGE_HIDE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_JUMP, 1.5f); - NavProfiles[GORGE_HIDE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALL, 1.0f); - NavProfiles[GORGE_HIDE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_LADDER, 1.0f); - NavProfiles[GORGE_HIDE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHFALL, 10.0f); - NavProfiles[GORGE_HIDE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHJUMP, 10.0f); - NavProfiles[GORGE_HIDE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f); - NavProfiles[GORGE_HIDE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 2.0f); - NavProfiles[GORGE_HIDE_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_MSTRUCTURE, 20.0f); - NavProfiles[GORGE_HIDE_NAV_PROFILE].bFlyingProfile = false; - NavProfiles[GORGE_HIDE_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_MARINE; - - NavProfiles[LERK_FLYING_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH; - NavProfiles[LERK_FLYING_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF); - NavProfiles[LERK_FLYING_NAV_PROFILE].Filters.setExcludeFlags(0); - NavProfiles[LERK_FLYING_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_ASTRUCTURE); - NavProfiles[LERK_FLYING_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_PHASEGATE); - NavProfiles[LERK_FLYING_NAV_PROFILE].Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD); - NavProfiles[LERK_FLYING_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f); - NavProfiles[LERK_FLYING_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_JUMP, 1.0f); - NavProfiles[LERK_FLYING_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_FALL, 1.0f); - NavProfiles[LERK_FLYING_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_WALLCLIMB, 1.0f); - NavProfiles[LERK_FLYING_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHFALL, 1.0f); - NavProfiles[LERK_FLYING_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_HIGHJUMP, 1.0f); - NavProfiles[LERK_FLYING_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f); - NavProfiles[LERK_FLYING_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_BLOCKED, 2.0f); - NavProfiles[LERK_FLYING_NAV_PROFILE].Filters.setAreaCost(SAMPLE_POLYAREA_MSTRUCTURE, 20.0f); - NavProfiles[LERK_FLYING_NAV_PROFILE].bFlyingProfile = true; - NavProfiles[LERK_FLYING_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_SKULK; - - NavProfiles[ALL_NAV_PROFILE].NavMeshIndex = REGULAR_NAV_MESH; - NavProfiles[ALL_NAV_PROFILE].Filters.setIncludeFlags(0xFFFF); - NavProfiles[ALL_NAV_PROFILE].Filters.setExcludeFlags(0); - NavProfiles[ALL_NAV_PROFILE].bFlyingProfile = false; - NavProfiles[ALL_NAV_PROFILE].ReachabilityFlag = AI_REACHABILITY_SKULK; + UTIL_PopulateBaseNavProfiles(); return true; } @@ -1106,12 +997,8 @@ bool NavmeshLoaded() Vector UTIL_GetRandomPointOnNavmesh(const AvHAIPlayer* pBot) { - int NavProfileIndex = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - - if (NavProfileIndex < 0) { return g_vecZero; } - - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(pBot->BotNavInfo.NavProfile); + const dtQueryFilter* m_navFilter = &pBot->BotNavInfo.NavProfile.Filters; if (!m_navQuery) { @@ -1141,7 +1028,7 @@ Vector UTIL_GetRandomPointOnNavmesh(const AvHAIPlayer* pBot) Vector UTIL_GetRandomPointOnNavmeshInRadiusOfAreaType(SamplePolyFlags Flag, const Vector origin, const float MaxRadius) { - const dtNavMeshQuery* m_NavQuery = UTIL_GetNavMeshQueryForProfile(ALL_NAV_PROFILE); + const dtNavMeshQuery* m_NavQuery = UTIL_GetNavMeshQueryForProfile(BaseNavProfiles[ALL_NAV_PROFILE]); if (!m_NavQuery) { return g_vecZero; } @@ -1181,10 +1068,10 @@ Vector UTIL_GetRandomPointOnNavmeshInRadiusOfAreaType(SamplePolyFlags Flag, cons return Result; } -Vector UTIL_GetRandomPointOnNavmeshInRadius(const int NavProfileIndex, const Vector origin, const float MaxRadius) +Vector UTIL_GetRandomPointOnNavmeshInRadius(const nav_profile &NavProfile, const Vector origin, const float MaxRadius) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); + const dtQueryFilter* m_navFilter = &NavProfile.Filters; if (!m_navQuery) { return g_vecZero; } @@ -1220,10 +1107,10 @@ Vector UTIL_GetRandomPointOnNavmeshInRadius(const int NavProfileIndex, const Vec return Result; } -Vector UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(const int NavProfileIndex, const Vector origin, const float MaxRadius) +Vector UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(const nav_profile& NavProfile, const Vector origin, const float MaxRadius) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); + const dtQueryFilter* m_navFilter = &NavProfile.Filters; if (!m_navQuery) { return g_vecZero; } @@ -1259,7 +1146,7 @@ Vector UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(const int NavProfi return Result; } -Vector UTIL_GetRandomPointOnNavmeshInDonut(const int NavProfile, const Vector origin, const float MinRadius, const float MaxRadius) +Vector UTIL_GetRandomPointOnNavmeshInDonut(const nav_profile& NavProfile, const Vector origin, const float MinRadius, const float MaxRadius) { int maxIterations = 0; float MinRadiusSq = sqrf(MinRadius); @@ -1279,7 +1166,7 @@ Vector UTIL_GetRandomPointOnNavmeshInDonut(const int NavProfile, const Vector or return g_vecZero; } -Vector UTIL_GetRandomPointOnNavmeshInDonutIgnoreReachability(const int NavProfile, const Vector origin, const float MinRadius, const float MaxRadius) +Vector UTIL_GetRandomPointOnNavmeshInDonutIgnoreReachability(const nav_profile& NavProfile, const Vector origin, const float MinRadius, const float MaxRadius) { int maxIterations = 0; float MinRadiusSq = sqrf(MinRadius); @@ -1304,13 +1191,13 @@ static float frand() return (float)rand() / (float)RAND_MAX; } -dtStatus FindPhaseGatePathToPoint(const int NavProfileIndex, Vector FromLocation, Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance) +dtStatus FindPhaseGatePathToPoint(const nav_profile& NavProfile, Vector FromLocation, Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance) { *pathSize = 0; - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfile); + const dtQueryFilter* m_navFilter = &NavProfile.Filters; if (!m_navQuery || vIsZero(FromLocation) || vIsZero(ToLocation)) { @@ -1340,14 +1227,14 @@ dtStatus FindPhaseGatePathToPoint(const int NavProfileIndex, Vector FromLocation if (TotalDist > vDist2DSq(FromLocation, ToLocation)) { return DT_FAILURE; } - dtStatus RouteToFirstPhaseGate = FindPathClosestToPoint(NavProfileIndex, FromLocation, StartPhaseGate->edict->v.origin, PathToPhaseStart, &PhaseStartPathSize, max_ai_use_reach); + dtStatus RouteToFirstPhaseGate = FindPathClosestToPoint(NavProfile, FromLocation, StartPhaseGate->edict->v.origin, PathToPhaseStart, &PhaseStartPathSize, max_ai_use_reach); if (dtStatusFailed(RouteToFirstPhaseGate)) { return DT_FAILURE; } - dtStatus RouteToFinalPoint = FindPathClosestToPoint(NavProfileIndex, EndPhaseGate->edict->v.origin, ToLocation, PathToFinalDestination, &PhaseEndPathSize, MaxAcceptableDistance); + dtStatus RouteToFinalPoint = FindPathClosestToPoint(NavProfile, EndPhaseGate->edict->v.origin, ToLocation, PathToFinalDestination, &PhaseEndPathSize, MaxAcceptableDistance); if (dtStatusFailed(RouteToFinalPoint)) { @@ -1365,7 +1252,7 @@ dtStatus FindPhaseGatePathToPoint(const int NavProfileIndex, Vector FromLocation // Add a node to inform the bot they have to use the phase gate path[CurrPathIndex].Location = EndPhaseGate->edict->v.origin + Vector(0.0f, 0.0f, 10.0f); - path[CurrPathIndex].area = SAMPLE_POLYAREA_PHASEGATE; + path[CurrPathIndex].area = SAMPLE_POLYAREA_GROUND; path[CurrPathIndex].flag = SAMPLE_POLYFLAGS_PHASEGATE; path[CurrPathIndex].poly = UTIL_GetNearestPolyRefForEntity(EndPhaseGate->edict); path[CurrPathIndex].requiredZ = EndPhaseGate->edict->v.origin.z; @@ -1384,13 +1271,11 @@ dtStatus FindPhaseGatePathToPoint(const int NavProfileIndex, Vector FromLocation } // Special path finding that takes flight movement into account -dtStatus FindFlightPathToPoint(const int NavProfileIndex, Vector FromLocation, Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance) +dtStatus FindFlightPathToPoint(const nav_profile &NavProfile, Vector FromLocation, Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance) { - if (NavProfileIndex < 0) { return DT_FAILURE; } - - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfile); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); + const dtQueryFilter* m_navFilter = &NavProfile.Filters; if (!m_navQuery || !m_navMesh || !m_navFilter || vIsZero(FromLocation) || vIsZero(ToLocation)) { @@ -1465,7 +1350,13 @@ dtStatus FindFlightPathToPoint(const int NavProfileIndex, Vector FromLocation, V unsigned char CurrArea; unsigned char ThisArea; + unsigned short CurrFlags; + unsigned short ThisFlags; + m_navMesh->getPolyArea(StraightPolyPath[0], &CurrArea); + m_navMesh->getPolyFlags(StraightPolyPath[0], &CurrFlags); + + CurrFlags &= ~(SAMPLE_POLYFLAGS_TEAM1STRUCTURE | SAMPLE_POLYFLAGS_TEAM2STRUCTURE); // At this point we have our path. Copy it to the path store int nIndex = 0; @@ -1486,6 +1377,9 @@ dtStatus FindFlightPathToPoint(const int NavProfileIndex, Vector FromLocation, V NextPathPoint.y = -StraightPath[nIndex++]; m_navMesh->getPolyArea(StraightPolyPath[nVert], &ThisArea); + m_navMesh->getPolyFlags(StraightPolyPath[nVert], &ThisFlags); + + ThisFlags &= ~(SAMPLE_POLYFLAGS_TEAM1STRUCTURE | SAMPLE_POLYFLAGS_TEAM2STRUCTURE); if (ThisArea == SAMPLE_POLYAREA_GROUND || ThisArea == SAMPLE_POLYAREA_CROUCH) { @@ -1503,7 +1397,7 @@ dtStatus FindFlightPathToPoint(const int NavProfileIndex, Vector FromLocation, V float NewRequiredZ = NextPathPoint.z; - if (CurrArea == SAMPLE_POLYAREA_WALLCLIMB || CurrArea == SAMPLE_POLYAREA_LADDER) + if (CurrFlags == SAMPLE_POLYFLAGS_WALLCLIMB || CurrFlags == SAMPLE_POLYFLAGS_LADDER) { NewRequiredZ = UTIL_FindZHeightForWallClimb(PrevPoint, NextPathPoint, head_hull); @@ -1511,7 +1405,7 @@ dtStatus FindFlightPathToPoint(const int NavProfileIndex, Vector FromLocation, V path[CurrentPathPoint].requiredZ = ClimbStartPoint.z; path[CurrentPathPoint].Location = ClimbStartPoint; - path[CurrentPathPoint].flag = straightPathFlags[nVert]; + path[CurrentPathPoint].flag = CurrFlags; path[CurrentPathPoint].area = CurrArea; path[CurrentPathPoint].poly = StraightPolyPath[nVert]; @@ -1522,7 +1416,7 @@ dtStatus FindFlightPathToPoint(const int NavProfileIndex, Vector FromLocation, V path[CurrentPathPoint].requiredZ = ClimbEndPoint.z; path[CurrentPathPoint].Location = ClimbEndPoint; - path[CurrentPathPoint].flag = straightPathFlags[nVert]; + path[CurrentPathPoint].flag = CurrFlags; path[CurrentPathPoint].area = CurrArea; path[CurrentPathPoint].poly = StraightPolyPath[nVert]; @@ -1530,14 +1424,14 @@ dtStatus FindFlightPathToPoint(const int NavProfileIndex, Vector FromLocation, V NumPathPoints++; } - if (CurrArea == SAMPLE_POLYAREA_JUMP || CurrArea == SAMPLE_POLYAREA_HIGHJUMP) + if (CurrFlags == SAMPLE_POLYFLAGS_JUMP) { float MaxHeight = fmaxf(PrevPoint.z, NextPathPoint.z); MaxHeight += 60.0f; path[CurrentPathPoint].requiredZ = MaxHeight; path[CurrentPathPoint].Location = Vector(PrevPoint.x, PrevPoint.y, MaxHeight); - path[CurrentPathPoint].flag = straightPathFlags[nVert]; + path[CurrentPathPoint].flag = CurrFlags; path[CurrentPathPoint].area = CurrArea; path[CurrentPathPoint].poly = StraightPolyPath[nVert]; @@ -1546,7 +1440,7 @@ dtStatus FindFlightPathToPoint(const int NavProfileIndex, Vector FromLocation, V path[CurrentPathPoint].requiredZ = MaxHeight; path[CurrentPathPoint].Location = Vector(NextPathPoint.x, NextPathPoint.y, MaxHeight); - path[CurrentPathPoint].flag = straightPathFlags[nVert]; + path[CurrentPathPoint].flag = CurrFlags; path[CurrentPathPoint].area = CurrArea; path[CurrentPathPoint].poly = StraightPolyPath[nVert]; @@ -1554,13 +1448,13 @@ dtStatus FindFlightPathToPoint(const int NavProfileIndex, Vector FromLocation, V NumPathPoints++; } - if (CurrArea == SAMPLE_POLYAREA_FALL || CurrArea == SAMPLE_POLYAREA_HIGHFALL) + if (CurrFlags == SAMPLE_POLYFLAGS_FALL) { Vector MidPoint = PrevPoint + ((NextPathPoint - PrevPoint) * 0.5f); path[CurrentPathPoint].requiredZ = PrevPoint.z; path[CurrentPathPoint].Location = Vector(MidPoint.x, MidPoint.y, PrevPoint.z); - path[CurrentPathPoint].flag = straightPathFlags[nVert]; + path[CurrentPathPoint].flag = CurrFlags; path[CurrentPathPoint].area = CurrArea; path[CurrentPathPoint].poly = StraightPolyPath[nVert]; @@ -1569,7 +1463,7 @@ dtStatus FindFlightPathToPoint(const int NavProfileIndex, Vector FromLocation, V path[CurrentPathPoint].requiredZ = NextPathPoint.z; path[CurrentPathPoint].Location = Vector(MidPoint.x, MidPoint.y, NextPathPoint.z); - path[CurrentPathPoint].flag = straightPathFlags[nVert]; + path[CurrentPathPoint].flag = CurrFlags; path[CurrentPathPoint].area = CurrArea; path[CurrentPathPoint].poly = StraightPolyPath[nVert]; @@ -1579,11 +1473,12 @@ dtStatus FindFlightPathToPoint(const int NavProfileIndex, Vector FromLocation, V path[CurrentPathPoint].requiredZ = NextPathPoint.z; path[CurrentPathPoint].Location = NextPathPoint; - path[CurrentPathPoint].flag = straightPathFlags[nVert]; + path[CurrentPathPoint].flag = CurrFlags; path[CurrentPathPoint].area = CurrArea; path[CurrentPathPoint].poly = StraightPolyPath[nVert]; CurrArea = ThisArea; + CurrFlags = ThisFlags; CurrentPathPoint++; } @@ -1639,13 +1534,11 @@ Vector UTIL_FindHighestSuccessfulTracePoint(const Vector TraceFrom, const Vector return CurrentHighest; } -dtStatus FindPathClosestToPoint(const int NavProfileIndex, const Vector FromLocation, const Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance) +dtStatus FindPathClosestToPoint(const nav_profile& NavProfile, const Vector FromLocation, const Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance) { - if (NavProfileIndex < 0) { return DT_FAILURE; } - - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfile); + const dtQueryFilter* m_navFilter = &NavProfile.Filters; if (!m_navQuery || !m_navMesh || !m_navFilter || vIsZero(FromLocation) || vIsZero(ToLocation)) { @@ -1717,11 +1610,16 @@ dtStatus FindPathClosestToPoint(const int NavProfileIndex, const Vector FromLoca int pathLengthInBytes = MAX_AI_PATH_SIZE * sizeof(bot_path_node); memset(path, 0, pathLengthInBytes); + unsigned short CurrFlags; unsigned char CurrArea; unsigned char ThisArea; + unsigned short ThisFlags; + m_navMesh->getPolyFlags(StraightPolyPath[0], &CurrFlags); m_navMesh->getPolyArea(StraightPolyPath[0], &CurrArea); + CurrFlags &= ~(SAMPLE_POLYFLAGS_TEAM1STRUCTURE | SAMPLE_POLYFLAGS_TEAM2STRUCTURE); + // At this point we have our path. Copy it to the path store int nIndex = 0; TraceResult hit; @@ -1737,7 +1635,10 @@ dtStatus FindPathClosestToPoint(const int NavProfileIndex, const Vector FromLoca path[(nVert)].Location.z = StraightPath[nIndex++]; path[(nVert)].Location.y = -StraightPath[nIndex++]; - m_navMesh->getPolyArea(StraightPolyPath[nVert], &ThisArea); + m_navMesh->getPolyArea(StraightPolyPath[nVert], &ThisArea); + m_navMesh->getPolyFlags(StraightPolyPath[nVert], &ThisFlags); + + ThisFlags &= ~(SAMPLE_POLYFLAGS_TEAM1STRUCTURE | SAMPLE_POLYFLAGS_TEAM2STRUCTURE); if (ThisArea == SAMPLE_POLYAREA_GROUND || ThisArea == SAMPLE_POLYAREA_CROUCH) { @@ -1754,7 +1655,7 @@ dtStatus FindPathClosestToPoint(const int NavProfileIndex, const Vector FromLoca { path[(nVert)].Location = hit.vecEndPos; - if (CurrArea != SAMPLE_POLYAREA_JUMP) + if (CurrFlags != SAMPLE_POLYFLAGS_JUMP) { path[(nVert)].Location.z += 20.0f; } @@ -1762,12 +1663,12 @@ dtStatus FindPathClosestToPoint(const int NavProfileIndex, const Vector FromLoca path[(nVert)].requiredZ = path[(nVert)].Location.z; - if (CurrArea == SAMPLE_POLYAREA_WALLCLIMB || CurrArea == SAMPLE_POLYAREA_LADDER) + if (CurrFlags == SAMPLE_POLYFLAGS_WALLCLIMB || CurrFlags == SAMPLE_POLYFLAGS_LADDER) { float NewRequiredZ = UTIL_FindZHeightForWallClimb(path[(nVert - 1)].Location, path[(nVert)].Location, head_hull); path[(nVert)].requiredZ = fmaxf(NewRequiredZ, path[(nVert)].Location.z); - if (CurrArea == SAMPLE_POLYAREA_LADDER) + if (CurrFlags == SAMPLE_POLYFLAGS_LADDER) { path[(nVert)].requiredZ += 5.0f; } @@ -1778,11 +1679,12 @@ dtStatus FindPathClosestToPoint(const int NavProfileIndex, const Vector FromLoca 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]; CurrArea = ThisArea; + CurrFlags = ThisFlags; NodeFromLocation = path[(nVert)].Location; } @@ -1792,161 +1694,13 @@ dtStatus FindPathClosestToPoint(const int NavProfileIndex, const Vector FromLoca return DT_SUCCESS; } -dtStatus FindDetailedPathClosestToPoint(const int NavProfileIndex, const Vector FromLocation, const Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance) -{ - if (NavProfileIndex < 0) { return DT_FAILURE; } - - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); - - if (!m_navQuery || !m_navMesh || !m_navFilter || vIsZero(FromLocation) || vIsZero(ToLocation)) - { - return DT_FAILURE; - } - - float pStartPos[3] = { FromLocation.x, FromLocation.z, -FromLocation.y }; - float pEndPos[3] = { ToLocation.x, ToLocation.z, -ToLocation.y }; - - dtStatus status; - dtPolyRef StartPoly; - float StartNearest[3]; - dtPolyRef EndPoly; - float EndNearest[3]; - dtPolyRef PolyPath[MAX_PATH_POLY]; - dtPolyRef StraightPolyPath[MAX_AI_PATH_SIZE]; - int nPathCount = 0; - float StraightPath[MAX_AI_PATH_SIZE * 3]; - unsigned char straightPathFlags[MAX_AI_PATH_SIZE]; - memset(straightPathFlags, 0, sizeof(straightPathFlags)); - int nVertCount = 0; - - // find the start polygon - status = m_navQuery->findNearestPoly(pStartPos, pExtents, m_navFilter, &StartPoly, StartNearest); - if ((status & DT_FAILURE) || (status & DT_STATUS_DETAIL_MASK)) - { - //BotSay(pBot, "findNearestPoly start failed!"); - return (status & DT_STATUS_DETAIL_MASK); // couldn't find a polygon - } - - // find the end polygon - status = m_navQuery->findNearestPoly(pEndPos, pExtents, m_navFilter, &EndPoly, EndNearest); - if ((status & DT_FAILURE) || (status & DT_STATUS_DETAIL_MASK)) - { - //BotSay(pBot, "findNearestPoly end failed!"); - return (status & DT_STATUS_DETAIL_MASK); // couldn't find a polygon - } - - status = m_navQuery->findPath(StartPoly, EndPoly, StartNearest, EndNearest, m_navFilter, PolyPath, &nPathCount, MAX_PATH_POLY); - - if (PolyPath[nPathCount - 1] != EndPoly) - { - float epos[3]; - dtVcopy(epos, EndNearest); - - m_navQuery->closestPointOnPoly(PolyPath[nPathCount - 1], EndNearest, epos, 0); - - if (dtVdistSqr(EndNearest, epos) > sqrf(MaxAcceptableDistance)) - { - return DT_FAILURE; - } - else - { - dtVcopy(EndNearest, epos); - } - } - - status = m_navQuery->findStraightPath(StartNearest, EndNearest, PolyPath, nPathCount, StraightPath, straightPathFlags, StraightPolyPath, &nVertCount, MAX_AI_PATH_SIZE, DT_STRAIGHTPATH_ALL_CROSSINGS); - if ((status & DT_FAILURE) || (status & DT_STATUS_DETAIL_MASK)) - { - return (status & DT_STATUS_DETAIL_MASK); // couldn't create a path - } - - if (nVertCount == 0) - { - return DT_FAILURE; // couldn't find a path - } - - int pathLengthInBytes = MAX_AI_PATH_SIZE * sizeof(bot_path_node); - memset(path, 0, pathLengthInBytes); - - unsigned char CurrArea; - unsigned char ThisArea; - - m_navMesh->getPolyArea(StraightPolyPath[0], &CurrArea); - - // At this point we have our path. Copy it to the path store - int nIndex = 0; - TraceResult hit; - Vector TraceStart; - - for (int nVert = 0; nVert < nVertCount; nVert++) - { - path[(nVert)].Location.x = StraightPath[nIndex++]; - path[(nVert)].Location.z = StraightPath[nIndex++]; - path[(nVert)].Location.y = -StraightPath[nIndex++]; - - m_navMesh->getPolyArea(StraightPolyPath[nVert], &ThisArea); - - if (ThisArea == SAMPLE_POLYAREA_GROUND || ThisArea == SAMPLE_POLYAREA_CROUCH) - { - path[(nVert)].Location = UTIL_AdjustPointAwayFromNavWall(path[(nVert)].Location, 16.0f); - } - - TraceStart.x = path[(nVert)].Location.x; - TraceStart.y = path[(nVert)].Location.y; - TraceStart.z = path[(nVert)].Location.z; - - UTIL_TraceLine(TraceStart, (TraceStart - Vector(0.0f, 0.0f, 100.0f)), ignore_monsters, ignore_glass, nullptr, &hit); - - if (hit.flFraction < 1.0f) - { - bool isCrouchedArea = (CurrArea == SAMPLE_POLYAREA_CROUCH); - - path[(nVert)].Location = hit.vecEndPos + Vector(0.0f, 0.0f, 18.0f); - } - - path[(nVert)].requiredZ = path[(nVert)].Location.z; - - if (CurrArea == SAMPLE_POLYAREA_WALLCLIMB || CurrArea == SAMPLE_POLYAREA_LADDER) - { - float NewRequiredZ = UTIL_FindZHeightForWallClimb(path[(nVert - 1)].Location, path[(nVert)].Location, head_hull); - path[(nVert)].requiredZ = fmaxf(NewRequiredZ, path[(nVert)].Location.z); - - if (CurrArea == SAMPLE_POLYAREA_LADDER) - { - path[(nVert)].requiredZ += 5.0f; - } - - } - else - { - path[(nVert)].requiredZ = path[(nVert)].Location.z; - } - - path[(nVert)].flag = straightPathFlags[nVert]; - path[(nVert)].area = CurrArea; - path[(nVert)].poly = StraightPolyPath[nVert]; - - CurrArea = ThisArea; - } - - *pathSize = nVertCount; - - return DT_SUCCESS; -} - dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle, const Vector FromLocation, const Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance) { if (!pBot) { return DT_FAILURE; } - int NavProfileIndex = UTIL_GetMoveProfileForBot(pBot, MoveStyle); - - if (NavProfileIndex < 0) { return DT_FAILURE; } - - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(pBot->BotNavInfo.NavProfile); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(pBot->BotNavInfo.NavProfile); + const dtQueryFilter* m_navFilter = &pBot->BotNavInfo.NavProfile.Filters; if (!m_navQuery || !m_navMesh || !m_navFilter || vIsZero(FromLocation) || vIsZero(ToLocation)) @@ -1961,7 +1715,7 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle, if (IsPlayerMarine(pBot->Edict) && AITAC_GetNumDeployablesNearLocation(ZERO_VECTOR, &PGFilter) > 1) { - dtStatus PhaseStatus = FindPhaseGatePathToPoint(NavProfileIndex, pBot->Edict->v.origin, ToLocation, path, pathSize, MaxAcceptableDistance); + dtStatus PhaseStatus = FindPhaseGatePathToPoint(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, ToLocation, path, pathSize, MaxAcceptableDistance); if (dtStatusSucceed(PhaseStatus)) { @@ -2035,10 +1789,14 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle, int pathLengthInBytes = MAX_AI_PATH_SIZE * sizeof(bot_path_node); memset(path, 0, pathLengthInBytes); + unsigned short CurrFlags; unsigned char CurrArea; + m_navMesh->getPolyFlags(StraightPolyPath[0], &CurrFlags); m_navMesh->getPolyArea(StraightPolyPath[0], &CurrArea); + CurrFlags &= ~(SAMPLE_POLYFLAGS_TEAM1STRUCTURE | SAMPLE_POLYFLAGS_TEAM2STRUCTURE); + // At this point we have our path. Copy it to the path store int nIndex = 0; TraceResult hit; @@ -2061,7 +1819,7 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle, TraceStart.y = path[(nVert)].Location.y; TraceStart.z = path[(nVert)].Location.z + 18.0f; - if (CurrArea != SAMPLE_POLYAREA_JUMP || path[(nVert)].FromLocation.z > path[(nVert)].Location.z) + if (CurrFlags != SAMPLE_POLYFLAGS_JUMP || path[(nVert)].FromLocation.z > path[(nVert)].Location.z) { UTIL_TraceHull(TraceStart, (TraceStart - Vector(0.0f, 0.0f, 100.0f)), ignore_monsters, head_hull, nullptr, &hit); @@ -2089,13 +1847,13 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle, // This what allows bots to climb over railings without having to explicitly place nav points on the railing itself path[(nVert)].requiredZ = path[(nVert)].Location.z; - if (CurrArea == SAMPLE_POLYAREA_WALLCLIMB || CurrArea == SAMPLE_POLYAREA_LADDER) + if (CurrFlags == SAMPLE_POLYFLAGS_WALLCLIMB || CurrFlags == SAMPLE_POLYFLAGS_LADDER) { int HullNum = GetPlayerHullIndex(pBot->Edict, false); float NewRequiredZ = UTIL_FindZHeightForWallClimb(path[(nVert - 1)].Location, path[(nVert)].Location, HullNum); path[(nVert)].requiredZ = fmaxf(NewRequiredZ, path[(nVert)].Location.z); - if (CurrArea == SAMPLE_POLYAREA_LADDER) + if (CurrFlags == SAMPLE_POLYFLAGS_LADDER) { path[(nVert)].requiredZ += 5.0f; } @@ -2110,7 +1868,10 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle, path[(nVert)].area = CurrArea; path[(nVert)].poly = StraightPolyPath[nVert]; - m_navMesh->getPolyArea(StraightPolyPath[nVert], &CurrArea); + m_navMesh->getPolyFlags(StraightPolyPath[nVert], &CurrFlags); + m_navMesh->getPolyArea(StraightPolyPath[0], &CurrArea); + + CurrFlags &= ~(SAMPLE_POLYFLAGS_TEAM1STRUCTURE | SAMPLE_POLYFLAGS_TEAM2STRUCTURE); NodeFromLocation = path[(nVert)].Location; } @@ -2120,11 +1881,11 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle, return DT_SUCCESS; } -bool UTIL_PointIsReachable(const int NavProfileIndex, const Vector FromLocation, const Vector ToLocation, const float MaxAcceptableDistance) +bool UTIL_PointIsReachable(const nav_profile &NavProfile, const Vector FromLocation, const Vector ToLocation, const float MaxAcceptableDistance) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfile); + const dtQueryFilter* m_navFilter = &NavProfile.Filters; if (!m_navQuery || vIsZero(FromLocation) || vIsZero(ToLocation)) { @@ -2190,7 +1951,7 @@ bool HasBotReachedPathPoint(const AvHAIPlayer* pBot) edict_t* pEdict = pBot->Edict; - int CurrentNavArea = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area; + SamplePolyFlags CurrentNavFlag = (SamplePolyFlags)pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].flag; Vector CurrentMoveDest = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].Location; Vector PrevMoveDest = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint - 1].Location; @@ -2206,9 +1967,9 @@ bool HasBotReachedPathPoint(const AvHAIPlayer* pBot) float playerRadius = GetPlayerRadius(pBot->Player); - switch (CurrentNavArea) + switch (CurrentNavFlag) { - case SAMPLE_POLYAREA_GROUND: + case SAMPLE_POLYFLAGS_WALK: if (!bIsAtFinalPathPoint) { return (bAtOrPastDestination || (vDist2D(pEdict->v.origin, CurrentMoveDest) <= 8.0f && (fabs(pBot->CurrentFloorPosition.z - CurrentMoveDest.z) < 50.0f))); @@ -2217,14 +1978,10 @@ bool HasBotReachedPathPoint(const AvHAIPlayer* pBot) { return ((vDist2D(pEdict->v.origin, CurrentMoveDest) < playerRadius && bDestIsDirectlyReachable) || bAtOrPastDestination); } - case SAMPLE_POLYAREA_CROUCH: - return (vDist2D(pEdict->v.origin, CurrentMoveDest) < playerRadius && bDestIsDirectlyReachable); - case SAMPLE_POLYAREA_BLOCKED: + case SAMPLE_POLYFLAGS_BLOCKED: return bAtOrPastDestination; - case SAMPLE_POLYAREA_FALL: - case SAMPLE_POLYAREA_HIGHFALL: - case SAMPLE_POLYAREA_JUMP: - case SAMPLE_POLYAREA_HIGHJUMP: + case SAMPLE_POLYFLAGS_FALL: + case SAMPLE_POLYFLAGS_JUMP: if (!bIsAtFinalPathPoint) { Vector thisMoveDir = UTIL_GetVectorNormal2D(pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].Location - pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint - 1].Location); @@ -2239,16 +1996,15 @@ bool HasBotReachedPathPoint(const AvHAIPlayer* pBot) else { return bAtOrPastDestination && pBot->BotNavInfo.IsOnGround && fabs(pBot->CurrentFloorPosition.z - CurrentMoveDest.z) < 50.0f; - //return (vDist2D(pEdict->v.origin, CurrentMoveDest) <= playerRadius && (fabs(pBot->CurrentFloorPosition.z - CurrentMoveDest.z) < 50.0f) && pBot->BotNavInfo.IsOnGround); } } else { return (vDist2D(pEdict->v.origin, CurrentMoveDest) <= playerRadius && (pEdict->v.origin.z - CurrentMoveDest.z) < 50.0f && pBot->BotNavInfo.IsOnGround); } - case SAMPLE_POLYAREA_WALLCLIMB: + case SAMPLE_POLYFLAGS_WALLCLIMB: return (bAtOrPastDestination && pBot->CollisionHullTopLocation.z > CurrentMoveDest.z); - case SAMPLE_POLYAREA_LADDER: + case SAMPLE_POLYFLAGS_LADDER: if (CurrentMoveDest.z > PrevMoveDest.z) { return ((BotPoly == DestinationPoly) && UTIL_QuickTrace(pEdict, pEdict->v.origin, CurrentMoveDest)); @@ -2391,17 +2147,12 @@ edict_t* UTIL_GetDoorBlockingPathPoint(bot_path_node* PathNode, edict_t* SearchD TraceResult doorHit; - if (PathNode->area == SAMPLE_POLYAREA_LADDER || PathNode->area == SAMPLE_POLYAREA_WALLCLIMB) + if (PathNode->flag == SAMPLE_POLYFLAGS_LADDER || PathNode->flag == SAMPLE_POLYFLAGS_WALLCLIMB) { Vector TargetLoc = Vector(FromLoc.x, FromLoc.y, PathNode->requiredZ); UTIL_TraceLine(FromLoc, TargetLoc, ignore_monsters, dont_ignore_glass, nullptr, &doorHit); - if (!FNullEnt(doorHit.pHit)) - { - const char* HitName = STRING(doorHit.pHit->v.classname); - } - if (!FNullEnt(SearchDoor)) { if (doorHit.pHit == SearchDoor) { return doorHit.pHit; } @@ -2424,11 +2175,6 @@ edict_t* UTIL_GetDoorBlockingPathPoint(bot_path_node* PathNode, edict_t* SearchD UTIL_TraceLine(TargetLoc, TargetLoc2, ignore_monsters, dont_ignore_glass, nullptr, &doorHit); - if (!FNullEnt(doorHit.pHit)) - { - const char* HitName2 = STRING(doorHit.pHit->v.classname); - } - if (!FNullEnt(SearchDoor)) { if (doorHit.pHit == SearchDoor) { return doorHit.pHit; } @@ -2447,17 +2193,12 @@ edict_t* UTIL_GetDoorBlockingPathPoint(bot_path_node* PathNode, edict_t* SearchD } } - else if (PathNode->area == SAMPLE_POLYAREA_FALL || PathNode->area == SAMPLE_POLYAREA_HIGHFALL) + else if (PathNode->flag == SAMPLE_POLYFLAGS_FALL) { Vector TargetLoc = Vector(ToLoc.x, ToLoc.y, FromLoc.z); UTIL_TraceLine(FromLoc, TargetLoc, ignore_monsters, dont_ignore_glass, nullptr, &doorHit); - if (!FNullEnt(doorHit.pHit)) - { - const char* HitName3 = STRING(doorHit.pHit->v.classname); - } - if (!FNullEnt(SearchDoor)) { if (doorHit.pHit == SearchDoor) { return doorHit.pHit; } @@ -2477,11 +2218,6 @@ 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); - if (!FNullEnt(doorHit.pHit)) - { - const char* HitName4 = STRING(doorHit.pHit->v.classname); - } - if (!FNullEnt(SearchDoor)) { if (doorHit.pHit == SearchDoor) { return doorHit.pHit; } @@ -2500,12 +2236,7 @@ edict_t* UTIL_GetDoorBlockingPathPoint(bot_path_node* PathNode, edict_t* SearchD } } - UTIL_TraceLine(FromLoc, ToLoc + Vector(0.0f, 0.0f, 10.0f), ignore_monsters, dont_ignore_glass, nullptr, &doorHit); - - if (!FNullEnt(doorHit.pHit)) - { - const char* HitName5 = STRING(doorHit.pHit->v.classname); - } + 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); if (!FNullEnt(SearchDoor)) { @@ -2528,7 +2259,236 @@ edict_t* UTIL_GetDoorBlockingPathPoint(bot_path_node* PathNode, edict_t* SearchD return nullptr; } -edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector ToLocation, const unsigned char Area, edict_t* SearchDoor) +edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* PathNode, edict_t* SearchBreakable) +{ + Vector FromLoc = PathNode->FromLocation; + Vector ToLoc = PathNode->Location; + + TraceResult breakableHit; + + if (PathNode->flag == SAMPLE_POLYFLAGS_LADDER || PathNode->flag == SAMPLE_POLYFLAGS_WALLCLIMB) + { + 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)) + { + if (breakableHit.pHit == SearchBreakable) { return breakableHit.pHit; } + } + else + { + if (!FNullEnt(breakableHit.pHit)) + { + if (strcmp(STRING(breakableHit.pHit->v.classname), "func_breakable") == 0) + { + return breakableHit.pHit; + } + } + + } + + 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)) + { + if (breakableHit.pHit == SearchBreakable) { return breakableHit.pHit; } + } + else + { + if (!FNullEnt(breakableHit.pHit)) + { + if (strcmp(STRING(breakableHit.pHit->v.classname), "func_breakable") == 0) + { + return breakableHit.pHit; + } + } + } + + } + else if (PathNode->flag == SAMPLE_POLYFLAGS_FALL) + { + 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)) + { + if (breakableHit.pHit == SearchBreakable) { return breakableHit.pHit; } + } + else + { + if (!FNullEnt(breakableHit.pHit)) + { + if (strcmp(STRING(breakableHit.pHit->v.classname), "func_breakable") == 0) + { + return breakableHit.pHit; + } + } + } + + 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)) + { + if (breakableHit.pHit == SearchBreakable) { return breakableHit.pHit; } + } + else + { + if (!FNullEnt(breakableHit.pHit)) + { + if (strcmp(STRING(breakableHit.pHit->v.classname), "func_breakable") == 0) + { + return breakableHit.pHit; + } + } + } + } + + UTIL_TraceLine(FromLoc, ToLoc, dont_ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &breakableHit); + UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc); + + + if (!FNullEnt(SearchBreakable)) + { + if (breakableHit.pHit == SearchBreakable) { return breakableHit.pHit; } + } + else + { + if (!FNullEnt(breakableHit.pHit)) + { + if (strcmp(STRING(breakableHit.pHit->v.classname), "func_breakable") == 0) + { + return breakableHit.pHit; + } + } + } + + + return nullptr; +} + +edict_t* UTIL_GetBreakableBlockingPathPoint(AvHAIPlayer* pBot, const Vector FromLocation, const Vector ToLocation, const unsigned short MovementFlag, edict_t* SearchBreakable) +{ + Vector FromLoc = FromLocation; + Vector ToLoc = ToLocation; + + TraceResult breakableHit; + + if (MovementFlag == SAMPLE_POLYFLAGS_LADDER || MovementFlag == SAMPLE_POLYFLAGS_WALLCLIMB) + { + 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)) + { + if (breakableHit.pHit == SearchBreakable) { return breakableHit.pHit; } + } + else + { + if (!FNullEnt(breakableHit.pHit)) + { + if (strcmp(STRING(breakableHit.pHit->v.classname), "func_breakable") == 0) + { + return breakableHit.pHit; + } + } + + } + + 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)) + { + if (breakableHit.pHit == SearchBreakable) { return breakableHit.pHit; } + } + else + { + if (!FNullEnt(breakableHit.pHit)) + { + if (strcmp(STRING(breakableHit.pHit->v.classname), "func_breakable") == 0) + { + return breakableHit.pHit; + } + } + } + + } + else if (MovementFlag == SAMPLE_POLYFLAGS_FALL) + { + 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)) + { + if (breakableHit.pHit == SearchBreakable) { return breakableHit.pHit; } + } + else + { + if (!FNullEnt(breakableHit.pHit)) + { + if (strcmp(STRING(breakableHit.pHit->v.classname), "func_breakable") == 0) + { + return breakableHit.pHit; + } + } + } + + 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)) + { + if (breakableHit.pHit == SearchBreakable) { return breakableHit.pHit; } + } + else + { + if (!FNullEnt(breakableHit.pHit)) + { + if (strcmp(STRING(breakableHit.pHit->v.classname), "func_breakable") == 0) + { + return breakableHit.pHit; + } + } + } + } + + UTIL_TraceLine(FromLoc, ToLoc, dont_ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &breakableHit); + UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc); + + if (!FNullEnt(SearchBreakable)) + { + if (breakableHit.pHit == SearchBreakable) { return breakableHit.pHit; } + } + else + { + if (!FNullEnt(breakableHit.pHit)) + { + if (strcmp(STRING(breakableHit.pHit->v.classname), "func_breakable") == 0) + { + return breakableHit.pHit; + } + } + } + + + return nullptr; +} + +edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector ToLocation, const unsigned short MovementFlag, edict_t* SearchDoor) { Vector FromLoc = FromLocation; @@ -2536,7 +2496,7 @@ edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector T TraceResult doorHit; - if (Area == SAMPLE_POLYAREA_LADDER || Area == SAMPLE_POLYAREA_WALLCLIMB) + if (MovementFlag == SAMPLE_POLYFLAGS_LADDER || MovementFlag == SAMPLE_POLYFLAGS_WALLCLIMB) { Vector TargetLoc = Vector(FromLoc.x, FromLoc.y, ToLocation.z); @@ -2564,11 +2524,6 @@ edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector T UTIL_TraceLine(TargetLoc, TargetLoc2, ignore_monsters, dont_ignore_glass, nullptr, &doorHit); - if (!FNullEnt(doorHit.pHit)) - { - const char* HitName2 = STRING(doorHit.pHit->v.classname); - } - if (!FNullEnt(SearchDoor)) { if (doorHit.pHit == SearchDoor) { return doorHit.pHit; } @@ -2587,17 +2542,12 @@ edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector T } } - else if (Area == SAMPLE_POLYAREA_FALL || Area == SAMPLE_POLYAREA_HIGHFALL) + else if (MovementFlag == SAMPLE_POLYFLAGS_FALL) { Vector TargetLoc = Vector(ToLoc.x, ToLoc.y, FromLoc.z); UTIL_TraceLine(FromLoc, TargetLoc, ignore_monsters, dont_ignore_glass, nullptr, &doorHit); - if (!FNullEnt(doorHit.pHit)) - { - const char* HitName3 = STRING(doorHit.pHit->v.classname); - } - if (!FNullEnt(SearchDoor)) { if (doorHit.pHit == SearchDoor) { return doorHit.pHit; } @@ -2617,10 +2567,6 @@ edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector T UTIL_TraceLine(TargetLoc, ToLoc + Vector(0.0f, 0.0f, 10.0f), ignore_monsters, dont_ignore_glass, nullptr, &doorHit); - if (!FNullEnt(doorHit.pHit)) - { - const char* HitName4 = STRING(doorHit.pHit->v.classname); - } if (!FNullEnt(SearchDoor)) { @@ -2642,11 +2588,6 @@ edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector T UTIL_TraceLine(FromLoc, ToLoc + Vector(0.0f, 0.0f, 10.0f), ignore_monsters, dont_ignore_glass, nullptr, &doorHit); - if (!FNullEnt(doorHit.pHit)) - { - const char* HitName5 = STRING(doorHit.pHit->v.classname); - } - if (!FNullEnt(SearchDoor)) { if (doorHit.pHit == SearchDoor) { return doorHit.pHit; } @@ -2670,7 +2611,7 @@ edict_t* UTIL_GetDoorBlockingPathPoint(const Vector FromLocation, const Vector T bool UTIL_IsPathBlockedByDoor(const Vector StartLoc, const Vector EndLoc, edict_t* SearchDoor) { - Vector ValidNavmeshPoint = UTIL_ProjectPointToNavmesh(EndLoc, MARINE_REGULAR_NAV_PROFILE); + Vector ValidNavmeshPoint = UTIL_ProjectPointToNavmesh(EndLoc, BaseNavProfiles[ALL_NAV_PROFILE]); if (!ValidNavmeshPoint) { @@ -2683,7 +2624,7 @@ bool UTIL_IsPathBlockedByDoor(const Vector StartLoc, const Vector EndLoc, edict_ // Now we find a path backwards from the valid nav mesh point to our location, trying to get as close as we can to it - dtStatus PathFindingStatus = FindPathClosestToPoint(MARINE_REGULAR_NAV_PROFILE, StartLoc, ValidNavmeshPoint, Path, &PathSize, 50.0f); + dtStatus PathFindingStatus = FindPathClosestToPoint(BaseNavProfiles[ALL_NAV_PROFILE], StartLoc, ValidNavmeshPoint, Path, &PathSize, 50.0f); if (dtStatusSucceed(PathFindingStatus)) { @@ -2737,74 +2678,74 @@ DoorTrigger* UTIL_GetNearestDoorTrigger(const Vector Location, nav_door* Door, C void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom, const Vector MoveTo) { - Vector MoveTarget = MoveTo; + edict_t* BlockingBreakableEdict = UTIL_GetBreakableBlockingPathPoint(pBot, pBot->Edict->v.origin, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].Location, SAMPLE_POLYAREA_GROUND, nullptr); - if (MoveTarget.z > pBot->Edict->v.origin.z) + if (FNullEnt(BlockingBreakableEdict)) { - MoveTarget.z += 32.0f; + if (pBot->BotNavInfo.CurrentPathPoint < pBot->BotNavInfo.PathSize - 1) + { + BlockingBreakableEdict = UTIL_GetBreakableBlockingPathPoint(pBot, &pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1], nullptr); + } + } + + if (FNullEnt(BlockingBreakableEdict)) + { + if (pBot->BotNavInfo.CurrentPathPoint < pBot->BotNavInfo.PathSize - 2) + { + BlockingBreakableEdict = UTIL_GetBreakableBlockingPathPoint(pBot, &pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 2], nullptr); + } + } + + if (FNullEnt(BlockingBreakableEdict)) + { + return; + } + + Vector ClosestPoint = UTIL_GetClosestPointOnEntityToLocation(pBot->Edict->v.origin, BlockingBreakableEdict); + + AvHAIWeapon DesiredWeapon = UTIL_GetBotPrimaryWeapon(pBot); + + if (IsPlayerMarine(pBot->Player)) + { + DesiredWeapon = BotMarineChooseBestWeapon(pBot, nullptr); } else { - MoveTarget.z -= 32.0f; - } - - Vector TraceDir = UTIL_GetVectorNormal(MoveTarget - pBot->Edict->v.origin); - - Vector TraceEnd = pBot->Edict->v.origin + (TraceDir * 50.0f); - - bool bBrokenGlass = false; - - TraceResult breakableHit; - UTIL_TraceLine(pBot->Edict->v.origin, TraceEnd, ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &breakableHit); - - if (breakableHit.flFraction < 1.0f) - { - if (strcmp(STRING(breakableHit.pHit->v.classname), "func_breakable") == 0) + if (IsPlayerSkulk(pBot->Edict)) { - pBot->desiredMovementDir = g_vecZero; - - bool bIsPlayerMarine = IsPlayerMarine(pBot->Edict); - AvHAIWeapon BreakWeapon = (bIsPlayerMarine) ? WEAPON_MARINE_KNIFE : UTIL_GetBotPrimaryWeapon(pBot); - - pBot->DesiredCombatWeapon = BreakWeapon; - - BotLookAt(pBot, breakableHit.pHit); - - if (GetBotCurrentWeapon(pBot) == BreakWeapon) - { - pBot->Button |= IN_ATTACK; - } - - bBrokenGlass = true; + DesiredWeapon = (BlockingBreakableEdict->v.health <= 20) ? WEAPON_SKULK_PARASITE : WEAPON_SKULK_BITE; } } - if (!bBrokenGlass) + float DesiredRange = GetMaxIdealWeaponRange(DesiredWeapon); + + if (vDist2DSq(pBot->Edict->v.origin, ClosestPoint) < sqrf(16.0f)) { - TraceEnd = pBot->Edict->v.origin + (pBot->desiredMovementDir * 50.0f); - - UTIL_TraceLine(pBot->Edict->v.origin - (pBot->desiredMovementDir * 10.0f), TraceEnd, dont_ignore_monsters, dont_ignore_glass, pBot->Edict->v.pContainingEntity, &breakableHit); - - if (breakableHit.flFraction < 1.0f) + if (pBot->Edict->v.oldbuttons & IN_DUCK) { - if (strcmp(STRING(breakableHit.pHit->v.classname), "func_breakable") == 0) + pBot->Button |= IN_DUCK; + } + else + { + if (pBot->CurrentEyePosition.z - ClosestPoint.z > 32.0f) { - pBot->desiredMovementDir = g_vecZero; - - bool bIsPlayerMarine = IsPlayerMarine(pBot->Edict); - AvHAIWeapon BreakWeapon = (bIsPlayerMarine) ? WEAPON_MARINE_KNIFE : UTIL_GetBotPrimaryWeapon(pBot); - - pBot->DesiredCombatWeapon = BreakWeapon; - - BotLookAt(pBot, breakableHit.pHit); - - if (GetBotCurrentWeapon(pBot) == BreakWeapon) - { - pBot->Button |= IN_ATTACK; - } + pBot->Button |= IN_DUCK; } } } + + if (vDist3DSq(ClosestPoint, pBot->CurrentEyePosition) < sqrf(DesiredRange)) + { + BotLookAt(pBot, BlockingBreakableEdict); + + pBot->DesiredMoveWeapon = DesiredWeapon; + + if (GetBotCurrentWeapon(pBot) == DesiredWeapon) + { + pBot->Button |= IN_ATTACK; + } + } + } void NewMove(AvHAIPlayer* pBot) @@ -2816,14 +2757,21 @@ void NewMove(AvHAIPlayer* pBot) } SamplePolyAreas CurrentNavArea = (SamplePolyAreas)pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area; + unsigned short CurrentNavFlags = (SamplePolyFlags)pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].flag; + + SamplePolyFlags CurrentNavFlag = (SamplePolyFlags)CurrentNavFlags; unsigned char NextArea = SAMPLE_POLYAREA_GROUND; + unsigned char NextFlag = SAMPLE_POLYFLAGS_WALK; if (pBot->BotNavInfo.CurrentPathPoint < (pBot->BotNavInfo.PathSize - 1)) { NextArea = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1].area; + NextFlag = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1].flag; } + bool bIsNearNextPoint = (pBot->BotNavInfo.CurrentPathPoint < (pBot->BotNavInfo.PathSize - 1)) && vDist2DSq(pBot->Edict->v.origin, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1].FromLocation) <= sqrf(50.0f); + Vector MoveFrom = g_vecZero; if (pBot->BotNavInfo.CurrentPathPoint > 0) @@ -2837,26 +2785,26 @@ void NewMove(AvHAIPlayer* pBot) Vector MoveTo = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].Location; - - - switch (CurrentNavArea) + if (CanPlayerCrouch(pBot->Edict) && (CurrentNavArea == SAMPLE_POLYAREA_CROUCH || (NextArea == SAMPLE_POLYAREA_CROUCH && bIsNearNextPoint))) { - case SAMPLE_POLYAREA_GROUND: - case SAMPLE_POLYAREA_CROUCH: + pBot->Button |= IN_DUCK; + } + + switch (CurrentNavFlag) + { + case SAMPLE_POLYFLAGS_WALK: GroundMove(pBot, MoveFrom, MoveTo); break; - case SAMPLE_POLYAREA_FALL: - case SAMPLE_POLYAREA_HIGHFALL: + case SAMPLE_POLYFLAGS_FALL: FallMove(pBot, MoveFrom, MoveTo); break; - case SAMPLE_POLYAREA_JUMP: - case SAMPLE_POLYAREA_HIGHJUMP: + case SAMPLE_POLYFLAGS_JUMP: JumpMove(pBot, MoveFrom, MoveTo); break; - case SAMPLE_POLYAREA_BLOCKED: + case SAMPLE_POLYFLAGS_BLOCKED: BlockedMove(pBot, MoveFrom, MoveTo); break; - case SAMPLE_POLYAREA_WALLCLIMB: + case SAMPLE_POLYFLAGS_WALLCLIMB: { if (IsPlayerSkulk(pBot->Edict)) { @@ -2868,10 +2816,10 @@ void NewMove(AvHAIPlayer* pBot) } } break; - case SAMPLE_POLYAREA_LADDER: + case SAMPLE_POLYFLAGS_LADDER: LadderMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].requiredZ, NextArea); break; - case SAMPLE_POLYAREA_PHASEGATE: + case SAMPLE_POLYFLAGS_PHASEGATE: PhaseGateMove(pBot, MoveFrom, MoveTo); break; default: @@ -2931,10 +2879,8 @@ void GroundMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin Vector endTrcLft = stTrcLft + (vForward * 24.0f); Vector endTrcRt = stTrcRt + (vForward * 24.0f); - int NavProfileIndex = UTIL_GetMoveProfileForBot(pBot, pBot->BotNavInfo.MoveStyle); - - bool bumpLeft = !UTIL_PointIsDirectlyReachable(NavProfileIndex, stTrcLft, endTrcLft); - bool bumpRight = !UTIL_PointIsDirectlyReachable(NavProfileIndex, stTrcRt, endTrcRt); + bool bumpLeft = !UTIL_PointIsDirectlyReachable(pBot->BotNavInfo.NavProfile, stTrcLft, endTrcLft); + bool bumpRight = !UTIL_PointIsDirectlyReachable(pBot->BotNavInfo.NavProfile, stTrcRt, endTrcRt); pBot->desiredMovementDir = vForward; @@ -2979,7 +2925,7 @@ void GroundMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin LeapDist = UTIL_MetresToGoldSrcUnits(1.0f); } - if (CanBotLeap(pBot) && vDist2DSq(pBot->Edict->v.origin, EndPoint) > sqrf(LeapDist) && UTIL_PointIsDirectlyReachable(NavProfileIndex, pBot->Edict->v.origin, EndPoint)) + if (CanBotLeap(pBot) && vDist2DSq(pBot->Edict->v.origin, EndPoint) > sqrf(LeapDist) && UTIL_PointIsDirectlyReachable(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, EndPoint)) { float CombatWeaponEnergyCost = GetEnergyCostForWeapon(pBot->DesiredCombatWeapon); float RequiredEnergy = (CombatWeaponEnergyCost + GetLeapCost(pBot)) - (GetPlayerEnergyRegenPerSecond(pEdict) * 0.5f); // We allow for around .5s of regen time as well @@ -3000,27 +2946,9 @@ void GroundMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin pBot->desiredMovementDir = UTIL_GetVectorNormal2D(pBot->desiredMovementDir); - bool bCanDuck = (IsPlayerMarine(pBot->Edict) || IsPlayerFade(pBot->Edict) || IsPlayerOnos(pBot->Edict)); - - if (!bCanDuck) { return; } - - // If this is a crouch type movement, then crouch - if (pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area == SAMPLE_POLYAREA_CROUCH) - { - pBot->Button |= IN_DUCK; - return; - } - - // Start ducking early if the next path point after this one is a crouch move - if ((pBot->BotNavInfo.CurrentPathPoint < (pBot->BotNavInfo.PathSize - 1)) && pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint + 1].area == SAMPLE_POLYAREA_CROUCH && vDist2DSq(pEdict->v.origin, EndPoint) < sqrf(50.0f)) - { - pBot->Button |= IN_DUCK; - return; - } - Vector HeadLocation = GetPlayerTopOfCollisionHull(pEdict, false); - // Also crouch if we have something in our way at head height + // Crouch if we have something in our way at head height if (!UTIL_QuickTrace(pBot->Edict, HeadLocation, (HeadLocation + (pBot->desiredMovementDir * 50.0f)))) { pBot->Button |= IN_DUCK; @@ -3394,7 +3322,7 @@ bool IsBotOffPath(const AvHAIPlayer* pBot) // If we're trying to use a phase gate, then we're fine as long as there is a phase gate within reach at the start and end teleport points - if (pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area == SAMPLE_POLYAREA_PHASEGATE) + if (pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].flag == SAMPLE_POLYFLAGS_PHASEGATE) { DeployableSearchFilter PGFilter; PGFilter.DeployableTypes = STRUCTURE_MARINE_PHASEGATE; @@ -3434,8 +3362,6 @@ bool IsBotOffPath(const AvHAIPlayer* pBot) } } - - float PlayerRadiusSq = sqrf(GetPlayerRadius(pBot->Player)); float PlayerHeight = GetPlayerHeight(pBot->Edict, false); @@ -3443,7 +3369,7 @@ bool IsBotOffPath(const AvHAIPlayer* pBot) Vector PointOnPath = vClosestPointOnLine2D(MoveFrom, MoveTo, pBot->CurrentFloorPosition); - if (pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area == SAMPLE_POLYAREA_WALLCLIMB) + if (pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].flag == SAMPLE_POLYFLAGS_WALLCLIMB) { return (vEquals(PointOnPath, MoveTo, 2.0f) && !IsPlayerClimbingWall(pBot->Edict) && pBot->CollisionHullTopLocation.z < MoveTo.z); } @@ -3454,7 +3380,7 @@ bool IsBotOffPath(const AvHAIPlayer* pBot) // TODO: This sucks - if (pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area == SAMPLE_POLYAREA_GROUND || pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area == SAMPLE_POLYAREA_CROUCH) + if (pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].flag == SAMPLE_POLYFLAGS_WALK) { bool bAtMoveStart = vEquals(PointOnPath, MoveFrom, 2.0f); @@ -3483,7 +3409,7 @@ bool IsBotOffPath(const AvHAIPlayer* pBot) return false; } - if (pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area == SAMPLE_POLYAREA_JUMP || pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area == SAMPLE_POLYAREA_HIGHJUMP) + if (pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].flag == SAMPLE_POLYFLAGS_JUMP) { Vector ExactJumpTarget = UTIL_GetGroundLocation(MoveTo); @@ -3495,7 +3421,7 @@ bool IsBotOffPath(const AvHAIPlayer* pBot) return false; } - if (pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area == SAMPLE_POLYAREA_FALL || pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area == SAMPLE_POLYAREA_HIGHFALL) + if (pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].flag == SAMPLE_POLYFLAGS_FALL) { if (vEquals(PointOnPath, MoveTo, 2.0f) && fabs(pBot->CurrentFloorPosition.z - MoveTo.z) > PlayerHeight) { @@ -3665,10 +3591,8 @@ void MoveDirectlyTo(AvHAIPlayer* pBot, const Vector Destination) Vector endTrcLft = stTrcLft + (vForward * 24.0f); Vector endTrcRt = stTrcRt + (vForward * 24.0f); - int NavProfileIndex = UTIL_GetMoveProfileForBot(pBot, pBot->BotNavInfo.MoveStyle); - - const bool bumpLeft = !UTIL_PointIsDirectlyReachable(NavProfileIndex, stTrcLft, endTrcLft); - const bool bumpRight = !UTIL_PointIsDirectlyReachable(NavProfileIndex, stTrcRt, endTrcRt); + const bool bumpLeft = !UTIL_PointIsDirectlyReachable(pBot->BotNavInfo.NavProfile, stTrcLft, endTrcLft); + const bool bumpRight = !UTIL_PointIsDirectlyReachable(pBot->BotNavInfo.NavProfile, stTrcRt, endTrcRt); pBot->desiredMovementDir = vForward; @@ -3733,11 +3657,9 @@ void MoveDirectlyTo(AvHAIPlayer* pBot, const Vector Destination) bool UTIL_PointIsDirectlyReachable(const AvHAIPlayer* pBot, const Vector targetPoint) { - int NavProfileIndex = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(pBot->BotNavInfo.NavProfile); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(pBot->BotNavInfo.NavProfile); + const dtQueryFilter* m_navFilter = &pBot->BotNavInfo.NavProfile.Filters; if (!m_navQuery) { return false; } @@ -3795,11 +3717,9 @@ bool UTIL_PointIsDirectlyReachable(const AvHAIPlayer* pBot, const Vector targetP bool UTIL_PointIsDirectlyReachable(const AvHAIPlayer* pBot, const Vector start, const Vector target) { - int NavProfileIndex = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(pBot->BotNavInfo.NavProfile); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(pBot->BotNavInfo.NavProfile); + const dtQueryFilter* m_navFilter = &pBot->BotNavInfo.NavProfile.Filters; if (!m_navQuery) { return false; } @@ -3852,56 +3772,32 @@ bool UTIL_PointIsDirectlyReachable(const AvHAIPlayer* pBot, const Vector start, } -const dtNavMesh* UTIL_GetNavMeshForProfile(const int NavProfileIndex) +const dtNavMesh* UTIL_GetNavMeshForProfile(const nav_profile& NavProfile) { - if (NavProfileIndex < 0 || NavProfileIndex >(MAX_NAV_PROFILES - 1)) { return nullptr; } + if (NavProfile.NavMeshIndex < 0 || NavProfile.NavMeshIndex >= MAX_NAV_MESHES) { return nullptr; } - if (NavProfiles[NavProfileIndex].NavMeshIndex > MAX_NAV_MESHES - 1) { return nullptr; } - - return NavMeshes[NavProfiles[NavProfileIndex].NavMeshIndex].navMesh; + return NavMeshes[NavProfile.NavMeshIndex].navMesh; } -const dtNavMeshQuery* UTIL_GetNavMeshQueryForProfile(const int NavProfileIndex) +const dtNavMeshQuery* UTIL_GetNavMeshQueryForProfile(const nav_profile& NavProfile) { - if (NavProfileIndex < 0 || NavProfileIndex >(MAX_NAV_PROFILES - 1)) { return nullptr; } + if (NavProfile.NavMeshIndex < 0 || NavProfile.NavMeshIndex >= MAX_NAV_MESHES) { return nullptr; } - if (NavProfiles[NavProfileIndex].NavMeshIndex > MAX_NAV_MESHES - 1) { return nullptr; } - - return NavMeshes[NavProfiles[NavProfileIndex].NavMeshIndex].navQuery; + return NavMeshes[NavProfile.NavMeshIndex].navQuery; } -const dtQueryFilter* UTIL_GetNavMeshFilterForProfile(const int NavProfileIndex) +const dtTileCache* UTIL_GetTileCacheForProfile(const nav_profile& NavProfile) { - if (NavProfileIndex < 0 || NavProfileIndex >(MAX_NAV_PROFILES - 1)) { return nullptr; } + if (NavProfile.NavMeshIndex < 0 || NavProfile.NavMeshIndex >= MAX_NAV_MESHES) { return nullptr; } - if (NavProfiles[NavProfileIndex].NavMeshIndex > MAX_NAV_MESHES - 1) { return nullptr; } - - return &NavProfiles[NavProfileIndex].Filters; + return NavMeshes[NavProfile.NavMeshIndex].tileCache; } -const dtTileCache* UTIL_GetTileCacheForProfile(const int NavProfileIndex) +bool UTIL_PointIsDirectlyReachable(const nav_profile &NavProfile, const Vector start, const Vector target) { - if (NavProfileIndex < 0 || NavProfileIndex >(MAX_NAV_PROFILES - 1)) { return nullptr; } - - if (NavProfiles[NavProfileIndex].NavMeshIndex > MAX_NAV_MESHES - 1) { return nullptr; } - - return NavMeshes[NavProfiles[NavProfileIndex].NavMeshIndex].tileCache; -} - -AvHAIReachabilityStatus UTIL_GetReachabilityFlagForProfile(const int NavProfileIndex) -{ - if (NavProfileIndex < 0 || NavProfileIndex >(MAX_NAV_PROFILES - 1)) { return AI_REACHABILITY_NONE; } - - if (NavProfiles[NavProfileIndex].NavMeshIndex > MAX_NAV_MESHES - 1) { return AI_REACHABILITY_NONE; } - - return NavProfiles[NavProfileIndex].ReachabilityFlag; -} - -bool UTIL_PointIsDirectlyReachable(const int NavProfileIndex, const Vector start, const Vector target) -{ - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfile); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); + const dtQueryFilter* m_navFilter = &NavProfile.Filters; if (!m_navMesh) { return false; } @@ -3969,11 +3865,11 @@ bool UTIL_PointIsDirectlyReachable(const int NavProfileIndex, const Vector start return (Height == 0.0f || Height == EndNearest[1]); } -bool UTIL_TraceNav(const int NavProfileIndex, const Vector start, const Vector target, const float MaxAcceptableDistance) +bool UTIL_TraceNav(const nav_profile &NavProfile, const Vector start, const Vector target, const float MaxAcceptableDistance) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtQueryFilter* m_Filter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfile); + const dtQueryFilter* m_Filter = &NavProfile.Filters; if (!m_navQuery) { return false; } @@ -4042,11 +3938,11 @@ bool UTIL_TraceNav(const int NavProfileIndex, const Vector start, const Vector t return (Height == 0.0f || Height == EndNearest[1]); } -void UTIL_TraceNavLine(const int NavProfileIndex, const Vector Start, const Vector End, nav_hitresult* HitResult) +void UTIL_TraceNavLine(const nav_profile &NavProfile, const Vector Start, const Vector End, nav_hitresult* HitResult) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtQueryFilter* m_Filter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfile); + const dtQueryFilter* m_Filter = &NavProfile.Filters; if (!m_navQuery) { @@ -4120,7 +4016,7 @@ void UTIL_TraceNavLine(const int NavProfileIndex, const Vector Start, const Vect Vector Dir = UTIL_GetVectorNormal(End - Start); Vector Point = Start + (Dir * HitResult->flFraction); - HitLocation = UTIL_ProjectPointToNavmesh(Point, Vector(100.0f, 100.0f, 100.0f), NavProfileIndex); + HitLocation = UTIL_ProjectPointToNavmesh(Point, Vector(100.0f, 100.0f, 100.0f), NavProfile); } HitResult->TraceEndPoint = HitLocation; @@ -4128,9 +4024,9 @@ void UTIL_TraceNavLine(const int NavProfileIndex, const Vector Start, const Vect bool UTIL_PointIsDirectlyReachable(const Vector start, const Vector target) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(ALL_NAV_PROFILE); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(ALL_NAV_PROFILE); - const dtQueryFilter* m_Filter = UTIL_GetNavMeshFilterForProfile(ALL_NAV_PROFILE); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(BaseNavProfiles[ALL_NAV_PROFILE]); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(BaseNavProfiles[ALL_NAV_PROFILE]); + const dtQueryFilter* m_Filter = &BaseNavProfiles[ALL_NAV_PROFILE].Filters; if (!m_navQuery) { return false; } @@ -4200,9 +4096,9 @@ bool UTIL_PointIsDirectlyReachable(const Vector start, const Vector target) float UTIL_PointIsDirectlyReachable_DEBUG(const Vector start, const Vector target) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(ALL_NAV_PROFILE); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(ALL_NAV_PROFILE); - const dtQueryFilter* m_Filter = UTIL_GetNavMeshFilterForProfile(ALL_NAV_PROFILE); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(BaseNavProfiles[ALL_NAV_PROFILE]); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(BaseNavProfiles[ALL_NAV_PROFILE]); + const dtQueryFilter* m_Filter = &BaseNavProfiles[ALL_NAV_PROFILE].Filters; if (!m_navQuery) { return 0.0f; } @@ -4281,11 +4177,11 @@ float UTIL_PointIsDirectlyReachable_DEBUG(const Vector start, const Vector targe return 2.2f; } -dtPolyRef UTIL_GetNearestPolyRefForLocation(const int NavProfileIndex, const Vector Location) +dtPolyRef UTIL_GetNearestPolyRefForLocation(const nav_profile& NavProfile, const Vector Location) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfile); + const dtQueryFilter* m_navFilter = &NavProfile.Filters; if (!m_navQuery) { return 0; } @@ -4303,9 +4199,9 @@ dtPolyRef UTIL_GetNearestPolyRefForLocation(const int NavProfileIndex, const Vec dtPolyRef UTIL_GetNearestPolyRefForLocation(const Vector Location) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(ALL_NAV_PROFILE); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(ALL_NAV_PROFILE); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(ALL_NAV_PROFILE); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(BaseNavProfiles[ALL_NAV_PROFILE]); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(BaseNavProfiles[ALL_NAV_PROFILE]); + const dtQueryFilter* m_navFilter = &BaseNavProfiles[ALL_NAV_PROFILE].Filters; if (!m_navQuery) { return 0; } @@ -4323,9 +4219,9 @@ dtPolyRef UTIL_GetNearestPolyRefForLocation(const Vector Location) dtPolyRef UTIL_GetNearestPolyRefForEntity(const edict_t* Edict) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(ALL_NAV_PROFILE); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(ALL_NAV_PROFILE); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(ALL_NAV_PROFILE); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(BaseNavProfiles[ALL_NAV_PROFILE]); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(BaseNavProfiles[ALL_NAV_PROFILE]); + const dtQueryFilter* m_navFilter = &BaseNavProfiles[ALL_NAV_PROFILE].Filters; if (!m_navQuery) { return 0; } @@ -4343,13 +4239,11 @@ dtPolyRef UTIL_GetNearestPolyRefForEntity(const edict_t* Edict) return result; } -unsigned char UTIL_GetNavAreaAtLocation(const int NavProfile, const Vector Location) +unsigned char UTIL_GetNavAreaAtLocation(const nav_profile &NavProfile, const Vector Location) { - if (NavProfile < 0 || NavProfile > MAX_NAV_PROFILES - 1) { return SAMPLE_POLYAREA_BLOCKED; } - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfile); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfile); + const dtQueryFilter* m_navFilter = &NavProfile.Filters; if (!m_navQuery) { return (unsigned char)SAMPLE_POLYAREA_BLOCKED; } @@ -4378,9 +4272,9 @@ unsigned char UTIL_GetNavAreaAtLocation(const int NavProfile, const Vector Locat unsigned char UTIL_GetNavAreaAtLocation(const Vector Location) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(ALL_NAV_PROFILE); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(ALL_NAV_PROFILE); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(ALL_NAV_PROFILE); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(BaseNavProfiles[ALL_NAV_PROFILE]); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(BaseNavProfiles[ALL_NAV_PROFILE]); + const dtQueryFilter* m_navFilter = &BaseNavProfiles[ALL_NAV_PROFILE].Filters; if (!m_navQuery) { return 0; } @@ -4415,24 +4309,8 @@ const char* UTIL_NavmeshAreaToChar(const unsigned char Area) return "Blocked"; case SAMPLE_POLYAREA_CROUCH: return "Crouch"; - case SAMPLE_POLYAREA_DOOR: - return "Door"; - case SAMPLE_POLYAREA_FALL: - return "Fall"; case SAMPLE_POLYAREA_GROUND: return "Ground"; - case SAMPLE_POLYAREA_HIGHFALL: - return "High Fall"; - case SAMPLE_POLYAREA_HIGHJUMP: - return "High Jump"; - case SAMPLE_POLYAREA_JUMP: - return "Jump"; - case SAMPLE_POLYAREA_LADDER: - return "Ladder"; - case SAMPLE_POLYAREA_WALLCLIMB: - return "Wall Climb"; - case SAMPLE_POLYAREA_WATER: - return "Water"; default: return "INVALID"; @@ -4441,87 +4319,6 @@ const char* UTIL_NavmeshAreaToChar(const unsigned char Area) return "INVALID"; } -int UTIL_GetMoveProfileForBot(const AvHAIPlayer* pBot, BotMoveStyle MoveStyle) -{ - AvHUser3 PlayerUser3 = pBot->Player->GetUser3(); - - switch (PlayerUser3) - { - case AVH_USER3_ALIEN_PLAYER1: - return UTIL_GetMoveProfileForSkulk(MoveStyle); - case AVH_USER3_ALIEN_PLAYER2: - return UTIL_GetMoveProfileForGorge(MoveStyle); - case AVH_USER3_ALIEN_PLAYER3: - return UTIL_GetMoveProfileForLerk(MoveStyle); - case AVH_USER3_ALIEN_PLAYER4: - return UTIL_GetMoveProfileForFade(MoveStyle); - case AVH_USER3_ALIEN_PLAYER5: - return UTIL_GetMoveProfileForOnos(MoveStyle); - default: - { - if (PlayerHasWeapon(pBot->Player, WEAPON_MARINE_WELDER)) - { - return MARINE_WELD_NAV_PROFILE; - } - else - { - return MARINE_REGULAR_NAV_PROFILE; - } - } - } -} - -int UTIL_GetMoveProfileForMarine(const BotMoveStyle MoveStyle) -{ - return MARINE_REGULAR_NAV_PROFILE; -} - -int UTIL_GetMoveProfileForSkulk(const BotMoveStyle MoveStyle) -{ - switch (MoveStyle) - { - case MOVESTYLE_AMBUSH: - case MOVESTYLE_HIDE: - return SKULK_AMBUSH_NAV_PROFILE; - default: - return SKULK_REGULAR_NAV_PROFILE; - } -} - -int UTIL_GetMoveProfileForGorge(const BotMoveStyle MoveStyle) -{ - switch (MoveStyle) - { - case MOVESTYLE_HIDE: - return GORGE_HIDE_NAV_PROFILE; - default: - return GORGE_REGULAR_NAV_PROFILE; - } -} - -int UTIL_GetMoveProfileForLerk(const BotMoveStyle MoveStyle) -{ - switch (MoveStyle) - { - case MOVESTYLE_NORMAL: - return LERK_FLYING_NAV_PROFILE; - default: - return GORGE_REGULAR_NAV_PROFILE; - } - - return GORGE_REGULAR_NAV_PROFILE; -} - -int UTIL_GetMoveProfileForFade(const BotMoveStyle MoveStyle) -{ - return FADE_REGULAR_NAV_PROFILE; -} - -int UTIL_GetMoveProfileForOnos(const BotMoveStyle MoveStyle) -{ - return ONOS_REGULAR_NAV_PROFILE; -} - void UTIL_UpdateBotMovementStatus(AvHAIPlayer* pBot) { if (pBot->Edict->v.movetype != pBot->BotNavInfo.CurrentMoveType) @@ -4559,7 +4356,7 @@ bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination) Vector MoveFrom = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint - 1].Location; Vector MoveTo = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].Location; - unsigned char area = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area; + unsigned short flag = pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].flag; Vector ClosestPointOnLine = vClosestPointOnLine2D(MoveFrom, MoveTo, pBot->Edict->v.origin); @@ -4574,7 +4371,7 @@ bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination) bool bReverseCourse = (vDist3DSq(DestinationPointOnLine, MoveFrom) < vDist3DSq(DestinationPointOnLine, MoveTo)); - if (area == SAMPLE_POLYAREA_GROUND || area == SAMPLE_POLYAREA_CROUCH) + if (flag == SAMPLE_POLYFLAGS_WALK) { if (UTIL_PointIsDirectlyReachable(pBot->Edict->v.origin, MoveFrom) || UTIL_PointIsDirectlyReachable(pBot->Edict->v.origin, MoveTo)) { @@ -4591,7 +4388,7 @@ bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination) } } - if (area == SAMPLE_POLYAREA_WALLCLIMB) + if (flag == SAMPLE_POLYFLAGS_WALLCLIMB) { if (bReverseCourse) { @@ -4603,7 +4400,7 @@ bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination) } } - if (area == SAMPLE_POLYAREA_LADDER) + if (flag == SAMPLE_POLYFLAGS_LADDER) { if (bReverseCourse) { @@ -4633,12 +4430,12 @@ bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination) } } - if (area == SAMPLE_POLYAREA_PHASEGATE) + if (flag == SAMPLE_POLYFLAGS_PHASEGATE) { return true; } - if (area == SAMPLE_POLYAREA_JUMP || area == SAMPLE_POLYAREA_HIGHJUMP || area == SAMPLE_POLYAREA_BLOCKED) + if (flag == SAMPLE_POLYFLAGS_JUMP || flag == SAMPLE_POLYFLAGS_BLOCKED) { if (bReverseCourse) { @@ -4650,7 +4447,7 @@ bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination) } } - if (area == SAMPLE_POLYAREA_FALL || area == SAMPLE_POLYAREA_HIGHFALL) + if (flag == SAMPLE_POLYFLAGS_FALL) { FallMove(pBot, MoveFrom, MoveTo); } @@ -4676,6 +4473,225 @@ bool IsBotPermaStuck(AvHAIPlayer* pBot) return (pBot->TimeSinceLastMovement >= 30.0f); } +void SetBaseNavProfile(AvHAIPlayer* pBot) +{ + pBot->BotNavInfo.bNavProfileChanged = true; + + if (IsPlayerMarine(pBot->Player)) + { + memcpy(&pBot->BotNavInfo.NavProfile, &BaseNavProfiles[MARINE_BASE_NAV_PROFILE], sizeof(nav_profile)); + return; + } + + switch (pBot->Edict->v.iuser3) + { + case AVH_USER3_ALIEN_PLAYER1: + memcpy(&pBot->BotNavInfo.NavProfile, &BaseNavProfiles[SKULK_BASE_NAV_PROFILE], sizeof(nav_profile)); + return; + case AVH_USER3_ALIEN_PLAYER2: + memcpy(&pBot->BotNavInfo.NavProfile, &BaseNavProfiles[GORGE_BASE_NAV_PROFILE], sizeof(nav_profile)); + return; + case AVH_USER3_ALIEN_PLAYER3: + memcpy(&pBot->BotNavInfo.NavProfile, &BaseNavProfiles[LERK_BASE_NAV_PROFILE], sizeof(nav_profile)); + return; + case AVH_USER3_ALIEN_PLAYER4: + memcpy(&pBot->BotNavInfo.NavProfile, &BaseNavProfiles[FADE_BASE_NAV_PROFILE], sizeof(nav_profile)); + return; + case AVH_USER3_ALIEN_PLAYER5: + memcpy(&pBot->BotNavInfo.NavProfile, &BaseNavProfiles[ONOS_BASE_NAV_PROFILE], sizeof(nav_profile)); + return; + + } +} + +void UpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) +{ + pBot->BotNavInfo.bNavProfileChanged = false; + + if (IsPlayerMarine(pBot->Player)) + { + MarineUpdateBotMoveProfile(pBot, MoveStyle); + return; + } + + switch (pBot->Edict->v.iuser3) + { + case AVH_USER3_ALIEN_PLAYER1: + SkulkUpdateBotMoveProfile(pBot, MoveStyle); + return; + case AVH_USER3_ALIEN_PLAYER2: + GorgeUpdateBotMoveProfile(pBot, MoveStyle); + return; + case AVH_USER3_ALIEN_PLAYER3: + LerkUpdateBotMoveProfile(pBot, MoveStyle); + return; + case AVH_USER3_ALIEN_PLAYER4: + FadeUpdateBotMoveProfile(pBot, MoveStyle); + return; + case AVH_USER3_ALIEN_PLAYER5: + OnosUpdateBotMoveProfile(pBot, MoveStyle); + return; + + } + +} + +void MarineUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) +{ + nav_profile* NavProfile = &pBot->BotNavInfo.NavProfile; + + bool bHasWelder = PlayerHasWeapon(pBot->Player, WEAPON_MARINE_WELDER); + + if (!bHasWelder) + { + AvHAIDroppedItem* NearbyWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, 0.0f, UTIL_MetresToGoldSrcUnits(10.0f), true); + + bHasWelder = (NearbyWelder != nullptr); + } + + bool bHadWelder = !(NavProfile->Filters.getExcludeFlags() & SAMPLE_POLYFLAGS_WELD); + + if (bHasWelder != bHadWelder) + { + pBot->BotNavInfo.bNavProfileChanged = true; + + if (bHasWelder) + { + NavProfile->Filters.removeExcludeFlags(SAMPLE_POLYFLAGS_WELD); + NavProfile->ReachabilityFlag = AI_REACHABILITY_WELDER; + } + else + { + NavProfile->Filters.addExcludeFlags(SAMPLE_POLYFLAGS_WELD); + NavProfile->ReachabilityFlag = AI_REACHABILITY_MARINE; + } + } + + if (MoveStyle == pBot->BotNavInfo.MoveStyle) { return; } + + pBot->BotNavInfo.bNavProfileChanged = true; + pBot->BotNavInfo.MoveStyle = MoveStyle; + + if (MoveStyle == MOVESTYLE_NORMAL) + { + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f); + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 2.0f); + return; + } + + if (MoveStyle == MOVESTYLE_HIDE || MoveStyle == MOVESTYLE_AMBUSH) + { + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 3.0f); + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f); + return; + } +} + +void SkulkUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) +{ + if (MoveStyle == pBot->BotNavInfo.MoveStyle) { return; } + + pBot->BotNavInfo.bNavProfileChanged = true; + pBot->BotNavInfo.MoveStyle = MoveStyle; + + nav_profile* NavProfile = &pBot->BotNavInfo.NavProfile; + + if (MoveStyle == MOVESTYLE_NORMAL) + { + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f); + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f); + return; + } + + if (MoveStyle == MOVESTYLE_HIDE || MoveStyle == MOVESTYLE_AMBUSH) + { + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 10.0f); + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f); + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_WALLCLIMB, 1.0f); + return; + } +} + +void GorgeUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) +{ + if (MoveStyle == pBot->BotNavInfo.MoveStyle) { return; } + + pBot->BotNavInfo.bNavProfileChanged = true; + pBot->BotNavInfo.MoveStyle = MoveStyle; + + nav_profile* NavProfile = &pBot->BotNavInfo.NavProfile; + + if (MoveStyle == MOVESTYLE_NORMAL) + { + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f); + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f); + return; + } + + if (MoveStyle == MOVESTYLE_HIDE || MoveStyle == MOVESTYLE_AMBUSH) + { + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 10.0f); + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f); + return; + } +} + +void LerkUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) +{ + if (MoveStyle == pBot->BotNavInfo.MoveStyle) { return; } + + pBot->BotNavInfo.bNavProfileChanged = true; + pBot->BotNavInfo.MoveStyle = MoveStyle; + + nav_profile* NavProfile = &pBot->BotNavInfo.NavProfile; + + if (MoveStyle == MOVESTYLE_NORMAL) + { + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f); + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f); + NavProfile->bFlyingProfile = true; + return; + } + + if (MoveStyle == MOVESTYLE_HIDE || MoveStyle == MOVESTYLE_AMBUSH) + { + NavProfile->bFlyingProfile = false; + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 10.0f); + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f); + return; + } +} + +void FadeUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) +{ + if (MoveStyle == pBot->BotNavInfo.MoveStyle) { return; } + + pBot->BotNavInfo.bNavProfileChanged = true; + pBot->BotNavInfo.MoveStyle = MoveStyle; + + nav_profile* NavProfile = &pBot->BotNavInfo.NavProfile; + + if (MoveStyle == MOVESTYLE_NORMAL) + { + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 1.0f); + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f); + return; + } + + if (MoveStyle == MOVESTYLE_HIDE || MoveStyle == MOVESTYLE_AMBUSH) + { + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_GROUND, 10.0f); + NavProfile->Filters.setAreaCost(SAMPLE_POLYAREA_CROUCH, 1.0f); + return; + } +} + +void OnosUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) +{ + // Onos doesn't really do much other than the usual movement + return; +} + bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle MoveStyle, const float MaxAcceptableDist) { nav_status* BotNavInfo = &pBot->BotNavInfo; @@ -4758,17 +4774,16 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move return true; } } - - int MoveProfile = UTIL_GetMoveProfileForBot(pBot, pBot->BotNavInfo.MoveStyle); - bool bIsFlyingProfile = NavProfiles[MoveProfile].bFlyingProfile; - - bool bMoveStyleChanged = (MoveStyle != pBot->BotNavInfo.MoveStyle); - bool bNavProfileChanged = (MoveProfile != pBot->BotNavInfo.LastMoveProfile); + + UpdateBotMoveProfile(pBot, MoveStyle); + + bool bIsFlyingProfile = pBot->BotNavInfo.NavProfile.bFlyingProfile; + bool bNavProfileChanged = pBot->BotNavInfo.bNavProfileChanged; 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 || (bMoveStyleChanged || bNavProfileChanged || bDestinationChanged || BotNavInfo->bPendingRecalculation)); + bool bShouldCalculatePath = bCanRecalculatePath && (BotNavInfo->PathSize == 0 || (bNavProfileChanged || bDestinationChanged || BotNavInfo->bPendingRecalculation)); if (bShouldCalculatePath) { @@ -4792,14 +4807,9 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move pBot->BotNavInfo.LastPathCalcTime = gpGlobals->time; BotNavInfo->bPendingRecalculation = false; - pBot->BotNavInfo.MoveStyle = MoveStyle; - pBot->BotNavInfo.LastMoveProfile = MoveProfile; - - - BotNavInfo->TargetDestination = Destination; - Vector ValidNavmeshPoint = UTIL_ProjectPointToNavmesh(Destination, Vector(max_ai_use_reach, max_ai_use_reach, max_ai_use_reach), MoveProfile); + Vector ValidNavmeshPoint = UTIL_ProjectPointToNavmesh(Destination, Vector(max_ai_use_reach, max_ai_use_reach, max_ai_use_reach), pBot->BotNavInfo.NavProfile); // Destination is not on the nav mesh, so we can't get close enough if (vIsZero(ValidNavmeshPoint)) @@ -4812,7 +4822,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move if (bIsFlyingProfile) { - PathFindingStatus = FindFlightPathToPoint(MoveProfile, pBot->CurrentFloorPosition, ValidNavmeshPoint, BotNavInfo->CurrentPath, &BotNavInfo->PathSize, MaxAcceptableDist); + PathFindingStatus = FindFlightPathToPoint(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, ValidNavmeshPoint, BotNavInfo->CurrentPath, &BotNavInfo->PathSize, MaxAcceptableDist); } else { @@ -4895,10 +4905,9 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move Vector FindClosestPointBackOnPath(AvHAIPlayer* pBot) { - int NavProfileIndex = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); DeployableSearchFilter ResNodeFilter; - ResNodeFilter.ReachabilityFlags = UTIL_GetReachabilityFlagForProfile(NavProfileIndex); + ResNodeFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag; AvHAIResourceNode* NearestResNode = AITAC_FindNearestResourceNodeToLocation(pBot->Edict->v.origin, &ResNodeFilter); @@ -4906,7 +4915,7 @@ Vector FindClosestPointBackOnPath(AvHAIPlayer* pBot) Vector ValidNavmeshPoint = NearestResNode->Location; - ValidNavmeshPoint = UTIL_ProjectPointToNavmesh(ValidNavmeshPoint, NavProfileIndex); + ValidNavmeshPoint = UTIL_ProjectPointToNavmesh(ValidNavmeshPoint, pBot->BotNavInfo.NavProfile); if (vIsZero(ValidNavmeshPoint)) { @@ -4919,7 +4928,7 @@ Vector FindClosestPointBackOnPath(AvHAIPlayer* pBot) // Now we find a path backwards from the valid nav mesh point to our location, trying to get as close as we can to it - dtStatus BackwardFindingStatus = FindPathClosestToPoint(NavProfileIndex, ValidNavmeshPoint, pBot->CurrentFloorPosition, BackwardsPath, &BackwardsPathSize, 500.0f); + dtStatus BackwardFindingStatus = FindPathClosestToPoint(pBot->BotNavInfo.NavProfile, ValidNavmeshPoint, pBot->CurrentFloorPosition, BackwardsPath, &BackwardsPathSize, 500.0f); if (dtStatusSucceed(BackwardFindingStatus)) { @@ -4940,7 +4949,7 @@ Vector FindClosestPointBackOnPath(AvHAIPlayer* pBot) return g_vecZero; } -Vector FindClosestNavigablePointToDestination(const int NavProfileIndex, const Vector FromLocation, const Vector ToLocation, float MaxAcceptableDistance) +Vector FindClosestNavigablePointToDestination(const nav_profile &NavProfile, const Vector FromLocation, const Vector ToLocation, float MaxAcceptableDistance) { bot_path_node Path[MAX_AI_PATH_SIZE]; memset(Path, 0, sizeof(Path)); @@ -4948,7 +4957,7 @@ Vector FindClosestNavigablePointToDestination(const int NavProfileIndex, const V // Now we find a path backwards from the valid nav mesh point to our location, trying to get as close as we can to it - dtStatus PathFindingResult = FindPathClosestToPoint(NavProfileIndex, FromLocation, ToLocation, Path, &PathSize, MaxAcceptableDistance); + dtStatus PathFindingResult = FindPathClosestToPoint(NavProfile, FromLocation, ToLocation, Path, &PathSize, MaxAcceptableDistance); if (dtStatusSucceed(PathFindingResult)) { @@ -5197,9 +5206,9 @@ void BotFollowPath(AvHAIPlayer* pBot) Vector TargetMoveLocation = BotNavInfo->CurrentPath[BotNavInfo->CurrentPathPoint].Location; - bool bIsUsingPhaseGate = (BotNavInfo->CurrentPath[BotNavInfo->CurrentPathPoint].area == SAMPLE_POLYAREA_PHASEGATE); + bool bIsUsingPhaseGate = (BotNavInfo->CurrentPath[BotNavInfo->CurrentPathPoint].flag == SAMPLE_POLYFLAGS_PHASEGATE); - bool bIsJumping = (BotNavInfo->CurrentPath[BotNavInfo->CurrentPathPoint].area == SAMPLE_POLYAREA_JUMP); + bool bIsJumping = (BotNavInfo->CurrentPath[BotNavInfo->CurrentPathPoint].flag == SAMPLE_POLYFLAGS_JUMP); if (bIsJumping) { @@ -5364,9 +5373,9 @@ bool BotIsAtLocation(const AvHAIPlayer* pBot, const Vector Destination) Vector UTIL_ProjectPointToNavmesh(const Vector Location) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(ALL_NAV_PROFILE); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(ALL_NAV_PROFILE); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(ALL_NAV_PROFILE); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(BaseNavProfiles[ALL_NAV_PROFILE]); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(BaseNavProfiles[ALL_NAV_PROFILE]); + const dtQueryFilter* m_navFilter = &BaseNavProfiles[ALL_NAV_PROFILE].Filters; if (!m_navQuery) { return g_vecZero; } @@ -5394,9 +5403,9 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location) Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(ALL_NAV_PROFILE); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(ALL_NAV_PROFILE); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(ALL_NAV_PROFILE); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(BaseNavProfiles[ALL_NAV_PROFILE]); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(BaseNavProfiles[ALL_NAV_PROFILE]); + const dtQueryFilter* m_navFilter = &BaseNavProfiles[ALL_NAV_PROFILE].Filters; if (!m_navQuery) { return g_vecZero; } @@ -5423,11 +5432,11 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents) } } -Vector UTIL_ProjectPointToNavmesh(const Vector Location, const int NavProfileIndex) +Vector UTIL_ProjectPointToNavmesh(const Vector Location, const nav_profile &NavProfile) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfile); + const dtQueryFilter* m_navFilter = &NavProfile.Filters; if (!m_navQuery) { return g_vecZero; } @@ -5448,11 +5457,11 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location, const int NavProfileInd } } -Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents, const int NavProfileIndex) +Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents, const nav_profile& NavProfile) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfile); + const dtQueryFilter* m_navFilter = &NavProfile.Filters; if (!m_navQuery) { return g_vecZero; } @@ -5475,11 +5484,11 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents, c } } -bool UTIL_PointIsOnNavmesh(const Vector Location, const int NavProfileIndex) +bool UTIL_PointIsOnNavmesh(const Vector Location, const nav_profile &NavProfile) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfile); + const dtQueryFilter* m_navFilter = &NavProfile.Filters; if (!m_navQuery) { return false; } @@ -5496,11 +5505,11 @@ bool UTIL_PointIsOnNavmesh(const Vector Location, const int NavProfileIndex) } -bool UTIL_PointIsOnNavmesh(const int NavProfileIndex, const Vector Location, const Vector SearchExtents) +bool UTIL_PointIsOnNavmesh(const nav_profile& NavProfile, const Vector Location, const Vector SearchExtents) { - const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfileIndex); - const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfileIndex); - const dtQueryFilter* m_navFilter = UTIL_GetNavMeshFilterForProfile(NavProfileIndex); + const dtNavMeshQuery* m_navQuery = UTIL_GetNavMeshQueryForProfile(NavProfile); + const dtNavMesh* m_navMesh = UTIL_GetNavMeshForProfile(NavProfile); + const dtQueryFilter* m_navFilter = &NavProfile.Filters; if (!m_navQuery) { return false; } @@ -5526,8 +5535,6 @@ void HandlePlayerAvoidance(AvHAIPlayer* pBot, const Vector MoveDestination) const Vector BotLocation = pBot->Edict->v.origin; const Vector MoveDir = UTIL_GetVectorNormal2D((MoveDestination - pBot->Edict->v.origin)); - const int NavProfileIndex = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - for (int i = 1; i <= gpGlobals->maxClients; i++) { edict_t* OtherPlayer = INDEXENT(i); @@ -5562,14 +5569,14 @@ void HandlePlayerAvoidance(AvHAIPlayer* pBot, const Vector MoveDestination) Vector PreferredMoveDir = (MoveRightVector * modifier); // First see if we have enough room to move in our preferred avoidance direction - if (UTIL_TraceNav(NavProfileIndex, BotLocation, BotLocation + (PreferredMoveDir * 32.0f), 2.0f)) + if (UTIL_TraceNav(pBot->BotNavInfo.NavProfile, BotLocation, BotLocation + (PreferredMoveDir * 32.0f), 2.0f)) { pBot->desiredMovementDir = PreferredMoveDir; return; } // Then try the opposite direction - if (UTIL_TraceNav(NavProfileIndex, BotLocation, BotLocation - (PreferredMoveDir * 32.0f), 2.0f)) + if (UTIL_TraceNav(pBot->BotNavInfo.NavProfile, BotLocation, BotLocation - (PreferredMoveDir * 32.0f), 2.0f)) { pBot->desiredMovementDir = -PreferredMoveDir; return; @@ -5586,12 +5593,12 @@ void HandlePlayerAvoidance(AvHAIPlayer* pBot, const Vector MoveDestination) } } -float UTIL_GetPathCostBetweenLocations(const int NavProfileIndex, const Vector FromLocation, const Vector ToLocation) +float UTIL_GetPathCostBetweenLocations(const nav_profile &NavProfile , const Vector FromLocation, const Vector ToLocation) { bot_path_node path[MAX_AI_PATH_SIZE]; int pathSize; - dtStatus pathFindResult = FindPathClosestToPoint(NavProfileIndex, FromLocation, ToLocation, path, &pathSize, max_ai_use_reach); + dtStatus pathFindResult = FindPathClosestToPoint(NavProfile, FromLocation, ToLocation, path, &pathSize, max_ai_use_reach); if (!dtStatusSucceed(pathFindResult)) { return 0.0f; } @@ -5601,7 +5608,7 @@ float UTIL_GetPathCostBetweenLocations(const int NavProfileIndex, const Vector F while (currPathPoint < (pathSize - 1)) { - result += vDist2DSq(path[currPathPoint - 1].Location, path[currPathPoint].Location) * NavProfiles[NavProfileIndex].Filters.getAreaCost(path[currPathPoint].area); + result += vDist2DSq(path[currPathPoint - 1].Location, path[currPathPoint].Location) * NavProfile.Filters.getAreaCost(path[currPathPoint].area); currPathPoint++; } @@ -5638,7 +5645,7 @@ bool BotRecalcPath(AvHAIPlayer* pBot, const Vector Destination) { ClearBotPath(pBot); - Vector ValidNavmeshPoint = UTIL_ProjectPointToNavmesh(Destination, Vector(max_ai_use_reach, max_ai_use_reach, max_ai_use_reach), pBot->BotNavInfo.MoveStyle); + Vector ValidNavmeshPoint = UTIL_ProjectPointToNavmesh(Destination, Vector(max_ai_use_reach, max_ai_use_reach, max_ai_use_reach), pBot->BotNavInfo.NavProfile); // We can't actually get close enough to this point to consider it "reachable" if (vIsZero(ValidNavmeshPoint)) @@ -5970,7 +5977,7 @@ void BotMovementInputs(AvHAIPlayer* pBot) pBot->Button |= IN_MOVELEFT; } - if (pBot->BotNavInfo.PathSize == 0 || pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].area != SAMPLE_POLYAREA_LADDER) + if (pBot->BotNavInfo.PathSize == 0 || pBot->BotNavInfo.CurrentPath[pBot->BotNavInfo.CurrentPathPoint].flag != SAMPLE_POLYFLAGS_LADDER) { if (pBot->Player->IsOnLadder()) { @@ -6099,7 +6106,7 @@ Vector UTIL_GetButtonFloorLocation(const Vector UserLocation, edict_t* ButtonEdi { Vector ClosestPoint = UTIL_GetClosestPointOnEntityToLocation(UserLocation, ButtonEdict); - Vector ButtonAccessPoint = UTIL_ProjectPointToNavmesh(ClosestPoint, Vector(100.0f, 100.0f, 100.0f), MARINE_REGULAR_NAV_PROFILE); + Vector ButtonAccessPoint = UTIL_ProjectPointToNavmesh(ClosestPoint, Vector(100.0f, 100.0f, 100.0f), BaseNavProfiles[ALL_NAV_PROFILE]); if (vIsZero(ButtonAccessPoint)) { @@ -6133,7 +6140,7 @@ Vector UTIL_GetButtonFloorLocation(const Vector UserLocation, edict_t* ButtonEdi NewProjection = ClosestPoint + Vector(0.0f, 0.0f, 100.0f); } - Vector NewButtonAccessPoint = UTIL_ProjectPointToNavmesh(NewProjection, MARINE_REGULAR_NAV_PROFILE); + Vector NewButtonAccessPoint = UTIL_ProjectPointToNavmesh(NewProjection, BaseNavProfiles[ALL_NAV_PROFILE]); if (vIsZero(NewButtonAccessPoint)) { @@ -6705,6 +6712,7 @@ void UTIL_PopulateDoors() } else { + NewDoor.TriggerEnts.clear(); UTIL_PopulateTriggersForEntity(currDoor->edict(), NewDoor.TriggerEnts); } @@ -6730,7 +6738,7 @@ void UTIL_PopulateDoors() } else { - NewDoor.ActivationType = DOOR_TRIGGER; + NewDoor.TriggerEnts.clear(); UTIL_PopulateTriggersForEntity(currDoor->edict(), NewDoor.TriggerEnts); } @@ -6755,7 +6763,7 @@ void UTIL_PopulateDoors() } else { - NewDoor.ActivationType = DOOR_TRIGGER; + NewDoor.TriggerEnts.clear(); UTIL_PopulateTriggersForEntity(currDoor->edict(), NewDoor.TriggerEnts); } diff --git a/main/source/mod/AIPlayers/AvHAINavigation.h b/main/source/mod/AIPlayers/AvHAINavigation.h index dae6ac8a..a6b18f1c 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.h +++ b/main/source/mod/AIPlayers/AvHAINavigation.h @@ -19,74 +19,48 @@ cannot wall climb, and has a higher cost for crouch movement since it's slower. */ -constexpr auto MARINE_REGULAR_NAV_PROFILE = 0; - -constexpr auto SKULK_REGULAR_NAV_PROFILE = 1; -constexpr auto SKULK_AMBUSH_NAV_PROFILE = 2; - -constexpr auto GORGE_REGULAR_NAV_PROFILE = 3; -constexpr auto GORGE_HIDE_NAV_PROFILE = 4; - -constexpr auto FADE_REGULAR_NAV_PROFILE = 5; - -constexpr auto ONOS_REGULAR_NAV_PROFILE = 6; - -constexpr auto BUILDING_REGULAR_NAV_PROFILE = 7; - -constexpr auto ALL_NAV_PROFILE = 8; - -constexpr auto LERK_FLYING_NAV_PROFILE = 9; - -constexpr auto GORGE_BUILD_NAV_PROFILE = 10; - -constexpr auto MARINE_WELD_NAV_PROFILE = 11; - 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 MARINE_BASE_NAV_PROFILE = 0; +constexpr auto SKULK_BASE_NAV_PROFILE = 1; +constexpr auto GORGE_BASE_NAV_PROFILE = 2; +constexpr auto LERK_BASE_NAV_PROFILE = 3; +constexpr auto FADE_BASE_NAV_PROFILE = 4; +constexpr auto ONOS_BASE_NAV_PROFILE = 5; +constexpr auto STRUCTURE_BASE_NAV_PROFILE = 6; +constexpr auto ALL_NAV_PROFILE = 7; #define MAX_PATH_POLY 512 // Max nav mesh polys that can be traversed in a path. This should be sufficient for any sized map. // Possible area types. Water, Road, Door and Grass are not used (left-over from Detour library) enum SamplePolyAreas { - SAMPLE_POLYAREA_GROUND = 0, // Regular ground movement - SAMPLE_POLYAREA_CROUCH = 1, // Requires crouched movement - SAMPLE_POLYAREA_WATER = 2, // Swimming (NOT USED) - SAMPLE_POLYAREA_BLOCKED = 3, // Requires a jump to get over - SAMPLE_POLYAREA_WALLCLIMB = 4, // Requires the ability to wall climb (i.e. skulks/fades/lerks only) - SAMPLE_POLYAREA_LADDER = 5, // Requires climbing a ladder (ignored by skulks) - SAMPLE_POLYAREA_DOOR = 6, // Requires moving through a door (NOT USED) - SAMPLE_POLYAREA_JUMP = 7, // Requires a jump to get through - SAMPLE_POLYAREA_HIGHJUMP = 8, // Requires jumping from a great height - SAMPLE_POLYAREA_FALL = 9, // Requires dropping down from a higher elevation - SAMPLE_POLYAREA_HIGHFALL = 10, // Requires a large drop from a high height - SAMPLE_POLYAREA_PHASEGATE = 11, // Requires accessing a phase gate (i.e. marines only) - SAMPLE_POLYAREA_MSTRUCTURE = 12, // Requires bypassing a marine structure - SAMPLE_POLYAREA_ASTRUCTURE = 13, // Requires bypassing an alien structure - SAMPLE_POLYAREA_FLY = 14, // Requires the ability to fly (currently lerks only) + SAMPLE_POLYAREA_GROUND = 0, // Regular ground movement + 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 }; // Possible movement types. Swim and door are not used enum SamplePolyFlags { - SAMPLE_POLYFLAGS_WALK = 1 << 0, // Simple walk to traverse - SAMPLE_POLYFLAGS_BLOCKED = 1 << 1, // Blocked by an obstruction, but can be jumped over - SAMPLE_POLYFLAGS_WALLCLIMB = 1 << 2, // Requires climbing a wall to traverse - SAMPLE_POLYFLAGS_LADDER = 1 << 3, // Requires climbing a ladder to traverse - SAMPLE_POLYFLAGS_DOOR = 1 << 4, // Requires opening a door to traverse (not used) - SAMPLE_POLYFLAGS_JUMP = 1 << 5, // Requires a jump to traverse - SAMPLE_POLYFLAGS_HIGHJUMP = 1 << 6, // Requires a jump from a high height to traverse - SAMPLE_POLYFLAGS_FALL = 1 << 7, // Requires dropping down from a safe height to traverse - SAMPLE_POLYFLAGS_HIGHFALL = 1 << 8, // Requires dropping from a high height to traverse - SAMPLE_POLYFLAGS_DISABLED = 1 << 9, // Disabled, not usable by anyone - SAMPLE_POLYFLAGS_NOONOS = 1 << 10, // This movement is not allowed by onos - SAMPLE_POLYFLAGS_PHASEGATE = 1 << 11, // Requires using a phase gate to traverse - SAMPLE_POLYFLAGS_MSTRUCTURE = 1 << 12, // Marine Structure in the way, must be destroyed if alien, or impassable if marine - SAMPLE_POLYFLAGS_ASTRUCTURE = 1 << 13, // Structure in the way, must be destroyed if marine, or impassable if alien - SAMPLE_POLYFLAGS_WELD = 1 << 14, // Requires a welder to get through here - SAMPLE_POLYFLAGS_ALL = 0xffff // All abilities. + SAMPLE_POLYFLAGS_WALK = 1 << 0, // Simple walk to traverse + SAMPLE_POLYFLAGS_FALL = 1 << 1, // Required dropping down + SAMPLE_POLYFLAGS_BLOCKED = 1 << 2, // Blocked by an obstruction, but can be jumped over + SAMPLE_POLYFLAGS_WALLCLIMB = 1 << 3, // Requires climbing a wall to traverse + SAMPLE_POLYFLAGS_LADDER = 1 << 4, // Requires climbing a ladder to traverse + SAMPLE_POLYFLAGS_JUMP = 1 << 5, // Requires a regular jump to traverse + SAMPLE_POLYFLAGS_DUCKJUMP = 1 << 6, // Requires a duck-jump to traverse + SAMPLE_POLYFLAGS_NOONOS = 1 << 7, // This movement is not allowed by onos + SAMPLE_POLYFLAGS_PHASEGATE = 1 << 8, // Requires using a phase gate to traverse + 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_DISABLED = 1 << 15, // Disabled, not usable by anyone + SAMPLE_POLYFLAGS_ALL = 0xffff // All abilities. }; // Door type. Not currently used, future feature so bots know how to open a door @@ -145,14 +119,6 @@ typedef struct _NAV_MESH class dtNavMesh* navMesh; } nav_mesh; -// A nav profile combines a nav mesh reference (indexed into NavMeshes) and filters to determine how a bot should find paths -typedef struct _NAV_PROFILE -{ - int NavMeshIndex = -1; - dtQueryFilter Filters; - bool bFlyingProfile = false; - AvHAIReachabilityStatus ReachabilityFlag = AI_REACHABILITY_NONE; -} nav_profile; static const int NAVMESHSET_MAGIC = 'M' << 24 | 'S' << 16 | 'E' << 8 | 'T'; //'MSET', used to confirm the nav mesh we're loading is compatible; static const int NAVMESHSET_VERSION = 1; @@ -181,7 +147,7 @@ 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 NavProfiles[MAX_NAV_PROFILES]; // Array of nav profiles +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(); @@ -196,6 +162,15 @@ bool LoadNavMesh(const char* mapname); // Unloads the nav meshes (UnloadNavMeshes()) and then reloads them (LoadNavMesh). Map data such as doors, hives, locations are not touched. void ReloadNavMeshes(); +void SetBaseNavProfile(AvHAIPlayer* pBot); +void UpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle); +void MarineUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle); +void SkulkUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle); +void GorgeUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle); +void LerkUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle); +void FadeUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle); +void OnosUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle); + // FUTURE FEATURE: Will eventually link a door to the trigger than opens it void UTIL_LinkTriggerToDoor(const edict_t* DoorEdict, nav_door* DoorRef); @@ -207,14 +182,14 @@ Vector UTIL_GetRandomPointOnNavmesh(const AvHAIPlayer* pBot); Returns ZERO_VECTOR if none found */ -Vector UTIL_GetRandomPointOnNavmeshInRadius(const int NavProfileIndex, const Vector origin, const float MaxRadius); +Vector UTIL_GetRandomPointOnNavmeshInRadius(const nav_profile& NavProfile, const Vector origin, const float MaxRadius); /* Finds any random point on the navmesh that is relevant for the bot within a given radius of the origin point, ignores reachability (could return a location that isn't actually reachable for the bot). Returns ZERO_VECTOR if none found */ -Vector UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(const int NavProfileIndex, const Vector origin, const float MaxRadius); +Vector UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(const nav_profile& NavProfile, const Vector origin, const float MaxRadius); /* Finds any random point on the navmesh of the area type (e.g. crouch area) that is relevant for the bot within a given radius of the origin point, taking reachability into account(will not return impossible to reach location). @@ -228,17 +203,17 @@ Vector UTIL_GetRandomPointOnNavmeshInRadiusOfAreaType(SamplePolyFlags Flag, cons Returns ZERO_VECTOR if none found */ -Vector UTIL_GetRandomPointOnNavmeshInDonut(const int NavProfile, const Vector origin, const float MinRadius, const float MaxRadius); +Vector UTIL_GetRandomPointOnNavmeshInDonut(const nav_profile& NavProfile, const Vector origin, const float MinRadius, const float MaxRadius); /* Finds any random point on the navmesh of the area type (e.g. crouch area) that is relevant for the bot within the min and max radius of the origin point, ignores reachability (could return a location that isn't actually reachable for the bot). Returns ZERO_VECTOR if none found */ -Vector UTIL_GetRandomPointOnNavmeshInDonutIgnoreReachability(const int NavProfile, const Vector origin, const float MinRadius, const float MaxRadius); +Vector UTIL_GetRandomPointOnNavmeshInDonutIgnoreReachability(const nav_profile& NavProfile, const Vector origin, const float MinRadius, const float MaxRadius); // Roughly estimates the movement cost to move between FromLocation and ToLocation. Uses simple formula of distance between points x cost modifier for that movement -float UTIL_GetPathCostBetweenLocations(const int NavProfileIndex, const Vector FromLocation, const Vector ToLocation); +float UTIL_GetPathCostBetweenLocations(const nav_profile &NavProfile, const Vector FromLocation, const Vector ToLocation); // Returns true is the bot is grounded, on the nav mesh, and close enough to the Destination to be considered at that point bool BotIsAtLocation(const AvHAIPlayer* pBot, const Vector Destination); @@ -275,7 +250,9 @@ DoorTrigger* UTIL_GetNearestDoorTrigger(const Vector Location, nav_door* Door, C 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(const Vector FromLocation, const Vector ToLocation, const unsigned char Area, 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); Vector UTIL_GetButtonFloorLocation(const Vector UserLocation, edict_t* ButtonEdict); @@ -292,7 +269,7 @@ bool IsBotStuck(AvHAIPlayer* pBot, const Vector MoveDestination); void UTIL_UpdateTileCache(); Vector UTIL_GetNearestPointOnNavWall(AvHAIPlayer* pBot, const float MaxRadius); -Vector UTIL_GetNearestPointOnNavWall(const int NavProfileIndex, const Vector Location, const float MaxRadius); +Vector UTIL_GetNearestPointOnNavWall(const nav_profile& NavProfile, const Vector Location, const float MaxRadius); /* Places a temporary obstacle of the given height and radius on the mesh.Will modify that part of the nav mesh to be the given area. An example use case is to place an obstacle of area type SAMPLE_POLYAREA_OBSTRUCTION to mark where buildings are. @@ -346,22 +323,21 @@ void MoveDirectlyTo(AvHAIPlayer* pBot, const Vector Destination); void HandlePlayerAvoidance(AvHAIPlayer* pBot, const Vector MoveDestination); // Special path finding that takes the presence of phase gates into account -dtStatus FindPhaseGatePathToPoint(const int NavProfileIndex, Vector FromLocation, Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance); +dtStatus FindPhaseGatePathToPoint(const nav_profile& NavProfile, Vector FromLocation, Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance); // Special path finding that takes the presence of phase gates into account -dtStatus FindFlightPathToPoint(const int NavProfileIndex, Vector FromLocation, Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance); +dtStatus FindFlightPathToPoint(const nav_profile& NavProfile, Vector FromLocation, Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance); Vector UTIL_FindHighestSuccessfulTracePoint(const Vector TraceFrom, const Vector TargetPoint, const Vector NextPoint, const float IterationStep, const float MinIdealHeight, const float MaxHeight); // Similar to FindPathToPoint, but you can specify a max acceptable distance for partial results. Will return a failure if it can't reach at least MaxAcceptableDistance away from the ToLocation dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle, const Vector FromLocation, const Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance); -dtStatus FindPathClosestToPoint(const int NavProfileIndex, const Vector FromLocation, const Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance); -dtStatus FindDetailedPathClosestToPoint(const int NavProfileIndex, const Vector FromLocation, const Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance); +dtStatus FindPathClosestToPoint(const nav_profile& NavProfile, const Vector FromLocation, const Vector ToLocation, bot_path_node* path, int* pathSize, float MaxAcceptableDistance); // If the bot is stuck and off the path or nav mesh, this will try to find a point it can directly move towards to get it back on track Vector FindClosestPointBackOnPath(AvHAIPlayer* pBot); -Vector FindClosestNavigablePointToDestination(const int NavProfileIndex, const Vector FromLocation, const Vector ToLocation, float MaxAcceptableDistance); +Vector FindClosestNavigablePointToDestination(const nav_profile& NavProfile, const Vector FromLocation, const Vector ToLocation, float MaxAcceptableDistance); // Will attempt to move directly towards MoveDestination while jumping/ducking as needed, and avoiding obstacles in the way void PerformUnstuckMove(AvHAIPlayer* pBot, const Vector MoveDestination); @@ -370,14 +346,11 @@ void PerformUnstuckMove(AvHAIPlayer* pBot, const Vector MoveDestination); static float frand(); // Finds the appropriate nav mesh for the requested profile -const dtNavMesh* UTIL_GetNavMeshForProfile(const int NavProfileIndex); +const dtNavMesh* UTIL_GetNavMeshForProfile(const nav_profile & NavProfile); // Finds the appropriate nav mesh query for the requested profile -const dtNavMeshQuery* UTIL_GetNavMeshQueryForProfile(const int NavProfileIndex); -// Finds the appropriate query filter for the requested profile -const dtQueryFilter* UTIL_GetNavMeshFilterForProfile(const int NavProfileIndex); +const dtNavMeshQuery* UTIL_GetNavMeshQueryForProfile(const nav_profile& NavProfile); // Finds the appropriatetile cache for the requested profile -const dtTileCache* UTIL_GetTileCacheForProfile(const int NavProfileIndex); -AvHAIReachabilityStatus UTIL_GetReachabilityFlagForProfile(const int NavProfileIndex); +const dtTileCache* UTIL_GetTileCacheForProfile(const nav_profile& NavProfile); float UTIL_PointIsDirectlyReachable_DEBUG(const Vector start, const Vector target); @@ -389,12 +362,12 @@ float UTIL_PointIsDirectlyReachable_DEBUG(const Vector start, const Vector targe bool UTIL_PointIsDirectlyReachable(const AvHAIPlayer* pBot, const Vector targetPoint); bool UTIL_PointIsDirectlyReachable(const AvHAIPlayer* pBot, const Vector start, const Vector target); bool UTIL_PointIsDirectlyReachable(const Vector start, const Vector target); -bool UTIL_PointIsDirectlyReachable(const int NavProfileIndex, const Vector start, const Vector target); +bool UTIL_PointIsDirectlyReachable(const nav_profile& NavProfile, const Vector start, const Vector target); // Will trace along the nav mesh from start to target and return true if the trace reaches within MaxAcceptableDistance -bool UTIL_TraceNav(const int NavProfileIndex, const Vector start, const Vector target, const float MaxAcceptableDistance); +bool UTIL_TraceNav(const nav_profile& NavProfile, const Vector start, const Vector target, const float MaxAcceptableDistance); -void UTIL_TraceNavLine(const int NavProfileIndex, const Vector Start, const Vector End, nav_hitresult* HitResult); +void UTIL_TraceNavLine(const nav_profile& NavProfile, const Vector Start, const Vector End, nav_hitresult* HitResult); /* Project point to navmesh: @@ -404,31 +377,21 @@ void UTIL_TraceNavLine(const int NavProfileIndex, const Vector Start, const Vect */ Vector UTIL_ProjectPointToNavmesh(const Vector Location); Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents); -Vector UTIL_ProjectPointToNavmesh(const Vector Location, const int NavProfileIndex); -Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents, const int NavProfileIndex); +Vector UTIL_ProjectPointToNavmesh(const Vector Location, const nav_profile& NavProfile); +Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents, const nav_profile& NavProfile); /* Point is on navmesh: Returns true if it was able to project the point to the navmesh (see UTIL_ProjectPointToNavmesh()) */ -bool UTIL_PointIsOnNavmesh(const Vector Location, const int NavProfileIndex); -bool UTIL_PointIsOnNavmesh(const int NavProfileIndex, const Vector Location, const Vector SearchExtents); - -int UTIL_GetMoveProfileForBot(const AvHAIPlayer* pBot, BotMoveStyle MoveStyle); - - -int UTIL_GetMoveProfileForMarine(const BotMoveStyle MoveStyle); -int UTIL_GetMoveProfileForSkulk(const BotMoveStyle MoveStyle); -int UTIL_GetMoveProfileForGorge(const BotMoveStyle MoveStyle); -int UTIL_GetMoveProfileForLerk(const BotMoveStyle MoveStyle); -int UTIL_GetMoveProfileForFade(const BotMoveStyle MoveStyle); -int UTIL_GetMoveProfileForOnos(const BotMoveStyle MoveStyle); +bool UTIL_PointIsOnNavmesh(const Vector Location, const nav_profile& NavProfile); +bool UTIL_PointIsOnNavmesh(const nav_profile& NavProfile, const Vector Location, const Vector SearchExtents); // Sets the BotNavInfo so the bot can track if it's on the ground, in the air, climbing a wall, on a ladder etc. void UTIL_UpdateBotMovementStatus(AvHAIPlayer* pBot); // Returns true if a path could be found between From and To location. Cheaper than full path finding, only a rough check to confirm it can be done. -bool UTIL_PointIsReachable(const int NavProfileIndex, const Vector FromLocation, const Vector ToLocation, const float MaxAcceptableDistance); +bool UTIL_PointIsReachable(const nav_profile& NavProfile, const Vector FromLocation, const Vector ToLocation, const float MaxAcceptableDistance); // If the bot has a path, it will work out how far along the path it can see and return the furthest point. Used so that the bot looks ahead along the path rather than just at its next path point Vector UTIL_GetFurthestVisiblePointOnPath(const AvHAIPlayer* pBot); @@ -439,11 +402,11 @@ Vector UTIL_GetFurthestVisiblePointOnPath(const Vector ViewerLocation, const bot // Returns the nearest nav mesh poly reference for the edict's current world position dtPolyRef UTIL_GetNearestPolyRefForEntity(const edict_t* Edict); dtPolyRef UTIL_GetNearestPolyRefForLocation(const Vector Location); -dtPolyRef UTIL_GetNearestPolyRefForLocation(const int NavProfileIndex, const Vector Location); +dtPolyRef UTIL_GetNearestPolyRefForLocation(const nav_profile& NavProfile, const Vector Location); // Returns the area for the nearest nav mesh poly to the given location. Returns BLOCKED if none found unsigned char UTIL_GetNavAreaAtLocation(const Vector Location); -unsigned char UTIL_GetNavAreaAtLocation(const int NavProfile, const Vector Location); +unsigned char UTIL_GetNavAreaAtLocation(const nav_profile& NavProfile, const Vector Location); // For printing out human-readable nav mesh areas const char* UTIL_NavmeshAreaToChar(const unsigned char Area); @@ -491,5 +454,7 @@ Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDis unsigned char UTIL_GetBotCurrentPathArea(AvHAIPlayer* pBot); unsigned char UTIL_GetNextBotCurrentPathArea(AvHAIPlayer* pBot); +void UTIL_PopulateBaseNavProfiles(); + #endif // BOT_NAVIGATION_H diff --git a/main/source/mod/AIPlayers/AvHAIPlayer.cpp b/main/source/mod/AIPlayers/AvHAIPlayer.cpp index 2bf74706..bcba3578 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayer.cpp +++ b/main/source/mod/AIPlayers/AvHAIPlayer.cpp @@ -257,9 +257,7 @@ void BotLeap(AvHAIPlayer* pBot, const Vector TargetLocation) Vector LookLocation = TargetLocation; - int NavProfileIndex = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - - unsigned char NavArea = UTIL_GetNavAreaAtLocation(NavProfileIndex, pBot->Edict->v.origin); + unsigned char NavArea = UTIL_GetNavAreaAtLocation(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin); if (NavArea == SAMPLE_POLYAREA_CROUCH) { @@ -377,7 +375,7 @@ void LinkDeployedObjectToCommanderAction(AvHAIPlayer* Commander, AvHAIBuildableS if (Action->NumDesiredInstances > 1) { - Action->BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(MARINE_REGULAR_NAV_PROFILE, Action->BuildLocation, UTIL_MetresToGoldSrcUnits(1.0f)); + Action->BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], Action->BuildLocation, UTIL_MetresToGoldSrcUnits(1.0f)); } Action->bIsAwaitingBuildLink = false; @@ -543,15 +541,13 @@ void BotAttackTarget(AvHAIPlayer* pBot, edict_t* Target) { Vector NewAttackLocation = ZERO_VECTOR; - int BotMoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - if (vIsZero(pBot->BotNavInfo.ActualMoveDestination)) { - NewAttackLocation = FindClosestNavigablePointToDestination(BotMoveProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(Target), WeaponRange); + NewAttackLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(Target), WeaponRange); } else { - NewAttackLocation = UTIL_GetRandomPointOnNavmeshInRadius(BotMoveProfile, pBot->CurrentFloorPosition, 2.0f); + NewAttackLocation = UTIL_GetRandomPointOnNavmeshInRadius(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, 2.0f); // Did we find a clear spot we could attack from? If so, make that our new move destination if (NewAttackLocation != ZERO_VECTOR && UTIL_TraceEntity(pBot->Edict, NewAttackLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_GetCentreOfEntity(Target)) == Target) @@ -1405,16 +1401,21 @@ void UpdateBotChat(AvHAIPlayer* pBot) } } -void StartNewBotFrame(AvHAIPlayer* pBot) +void ClearBotInputs(AvHAIPlayer* pBot) { - edict_t* pEdict = pBot->Edict; - pBot->Button = 0; pBot->ForwardMove = 0.0f; pBot->SideMove = 0.0f; pBot->UpMove = 0.0f; pBot->Impulse = 0; pBot->Button = 0; +} + +void StartNewBotFrame(AvHAIPlayer* pBot) +{ + edict_t* pEdict = pBot->Edict; + + ClearBotInputs(pBot); pBot->CurrentEyePosition = GetPlayerEyePosition(pEdict); pBot->CurrentFloorPosition = UTIL_GetEntityGroundLocation(pEdict); pBot->LookTargetLocation = ZERO_VECTOR; @@ -1482,15 +1483,13 @@ void TestNavThink(AvHAIPlayer* pBot) } else { - int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - AvHAIResourceNode* RandomNode = AITAC_GetRandomResourceNode(); if (!RandomNode) { return; } Vector RandomPoint = RandomNode->Location; - if (RandomPoint != ZERO_VECTOR && UTIL_PointIsReachable(MoveProfile, pBot->Edict->v.origin, RandomPoint, max_player_use_reach)) + if (RandomPoint != ZERO_VECTOR && UTIL_PointIsReachable(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, RandomPoint, max_player_use_reach)) { AITASK_SetMoveTask(pBot, &pBot->PrimaryBotTask, RandomPoint, true); } @@ -1505,4 +1504,17 @@ void BotSwitchToWeapon(AvHAIPlayer* pBot, AvHAIWeapon NewWeaponSlot) { char* WeaponName = UTIL_WeaponTypeToClassname(NewWeaponSlot); pBot->Player->SwitchWeapon(WeaponName); +} + +bool ShouldBotThink(AvHAIPlayer* pBot) +{ + return IsPlayerActiveInGame(pBot->Edict) && !IsPlayerGestating(pBot->Edict); +} + +void BotResumePlay(AvHAIPlayer* pBot) +{ + ClearBotMovement(pBot); + SetBaseNavProfile(pBot); + + pBot->bIsInactive = false; } \ No newline at end of file diff --git a/main/source/mod/AIPlayers/AvHAIPlayer.h b/main/source/mod/AIPlayers/AvHAIPlayer.h index de5beb7c..f2f82301 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayer.h +++ b/main/source/mod/AIPlayers/AvHAIPlayer.h @@ -50,6 +50,7 @@ Vector GetVisiblePointOnPlayerFromObserver(edict_t* Observer, edict_t* TargetPla void UpdateBotChat(AvHAIPlayer* pBot); +void ClearBotInputs(AvHAIPlayer* pBot); void StartNewBotFrame(AvHAIPlayer* pBot); void TestNavThink(AvHAIPlayer* pBot); @@ -57,4 +58,8 @@ void DroneThink(AvHAIPlayer* pBot); void BotSwitchToWeapon(AvHAIPlayer* pBot, AvHAIWeapon NewWeaponSlot); +bool ShouldBotThink(AvHAIPlayer* pBot); + +void BotResumePlay(AvHAIPlayer* pBot); + #endif \ No newline at end of file diff --git a/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp b/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp index 96b27415..add4f3c4 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp +++ b/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp @@ -5,6 +5,7 @@ #include "AvHAINavigation.h" #include "AvHAIConfig.h" #include "AvHAIWeaponHelper.h" +#include "AvHAIHelper.h" #include "../AvHGamerules.h" #include "../dlls/client.h" #include @@ -26,6 +27,8 @@ int BotNameIndex = 0; float AIStartedTime = 0.0f; // Used to give 5-second grace period before adding bots +extern int m_spriteTexture; + string BotNames[MAX_PLAYERS] = { "MrRobot", "Wall-E", "BeepBoop", @@ -503,20 +506,33 @@ void AIMGR_UpdateAIPlayers() { BotDeltaTime = ThinkDelta; - StartNewBotFrame(bot); - - UpdateBotChat(bot); - - DroneThink(bot); - - AvHAIWeapon DesiredWeapon = (bot->DesiredMoveWeapon != WEAPON_NONE) ? bot->DesiredMoveWeapon : bot->DesiredCombatWeapon; - - if (DesiredWeapon != WEAPON_NONE && GetBotCurrentWeapon(bot) != DesiredWeapon) + if (ShouldBotThink(bot)) { - BotSwitchToWeapon(bot, DesiredWeapon); - } + if (bot->bIsInactive) + { + BotResumePlay(bot); + } - BotUpdateDesiredViewRotation(bot); + StartNewBotFrame(bot); + + UpdateBotChat(bot); + + DroneThink(bot); + + AvHAIWeapon DesiredWeapon = (bot->DesiredMoveWeapon != WEAPON_NONE) ? bot->DesiredMoveWeapon : bot->DesiredCombatWeapon; + + if (DesiredWeapon != WEAPON_NONE && GetBotCurrentWeapon(bot) != DesiredWeapon) + { + BotSwitchToWeapon(bot, DesiredWeapon); + } + + BotUpdateDesiredViewRotation(bot); + } + else + { + ClearBotInputs(bot); + bot->bIsInactive = true; + } // Needed to correctly handle client prediction and physics calculations byte adjustedmsec = BotThrottledMsec(bot); @@ -642,6 +658,8 @@ void AIMGR_NewMap() { return; } + + AIMGR_BotPrecache(); } AvHAIPlayer* AIMGR_GetAICommander(AvHTeamNumber Team) @@ -716,4 +734,9 @@ void AIMGR_UpdateAIMapData() { UTIL_UpdateTileCache(); AITAC_UpdateMapAIData(); +} + +void AIMGR_BotPrecache() +{ + m_spriteTexture = PRECACHE_MODEL("sprites/zbeam6.spr"); } \ No newline at end of file diff --git a/main/source/mod/AIPlayers/AvHAIPlayerManager.h b/main/source/mod/AIPlayers/AvHAIPlayerManager.h index d16f5c5f..1c124b3f 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayerManager.h +++ b/main/source/mod/AIPlayers/AvHAIPlayerManager.h @@ -9,6 +9,7 @@ static const double BOT_MIN_FRAME_TIME = (1.0 / 60.0); // At map load / map restart, how long to wait before starting to add bots static const float AI_GRACE_PERIOD = 5.0f; +void AIMGR_BotPrecache(); // Called when the round restarts. Clears all tactical information but keeps navigation data. void AIMGR_ResetRound(); diff --git a/main/source/mod/AIPlayers/AvHAIPlayerUtil.cpp b/main/source/mod/AIPlayers/AvHAIPlayerUtil.cpp index 1b86fabc..935d7aaa 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayerUtil.cpp +++ b/main/source/mod/AIPlayers/AvHAIPlayerUtil.cpp @@ -206,6 +206,23 @@ float GetPlayerRadius(const AvHPlayer* Player) } } +bool CanPlayerCrouch(const edict_t* Player) +{ + if (FNullEnt(Player) || Player->free || !IsEdictPlayer(Player)) { return false; } + + switch (Player->v.iuser3) + { + case AVH_USER3_ALIEN_PLAYER1: + case AVH_USER3_ALIEN_PLAYER2: + case AVH_USER3_ALIEN_PLAYER3: + return false; + default: + return true; + } + + return false; +} + int GetPlayerHullIndex(const edict_t* Player, const bool bIsCrouching) { if (!Player) { return 0; } @@ -642,34 +659,36 @@ bool PlayerHasWeapon(const AvHPlayer* Player, const AvHAIWeapon DesiredCombatWea case WEAPON_LERK_BITE: case WEAPON_FADE_SWIPE: case WEAPON_ONOS_GORE: - DesiredWeaponIndex = 0; + DesiredWeaponIndex = 1; break; case WEAPON_SKULK_PARASITE: case WEAPON_GORGE_HEALINGSPRAY: case WEAPON_LERK_SPORES: case WEAPON_FADE_BLINK: case WEAPON_ONOS_DEVOUR: - DesiredWeaponIndex = 1; + DesiredWeaponIndex = 2; break; case WEAPON_SKULK_LEAP: case WEAPON_GORGE_BILEBOMB: case WEAPON_LERK_UMBRA: case WEAPON_FADE_METABOLIZE: case WEAPON_ONOS_STOMP: - DesiredWeaponIndex = 2; + DesiredWeaponIndex = 3; break; case WEAPON_SKULK_XENOCIDE: case WEAPON_GORGE_WEB: case WEAPON_LERK_PRIMALSCREAM: case WEAPON_FADE_ACIDROCKET: case WEAPON_ONOS_CHARGE: - DesiredWeaponIndex = 3; + DesiredWeaponIndex = 4; break; default: DesiredWeaponIndex = -1; break; } + if (DesiredWeaponIndex < 0) { return false; } + AvHBasePlayerWeapon* Weapon = dynamic_cast(Player->m_rgpPlayerItems[DesiredWeaponIndex]); return (Weapon && Weapon->m_iEnabled); diff --git a/main/source/mod/AIPlayers/AvHAIPlayerUtil.h b/main/source/mod/AIPlayers/AvHAIPlayerUtil.h index 10937456..bdf1fb2c 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayerUtil.h +++ b/main/source/mod/AIPlayers/AvHAIPlayerUtil.h @@ -77,6 +77,8 @@ int GetPlayerMaxArmour(const edict_t* Player); // Returns the player's current energy (between 0.0 and 1.0) float GetPlayerEnergy(const edict_t* Player); +// Can the player duck? Skulks, gorges and lerks cannot +bool CanPlayerCrouch(const edict_t* Player); // Returns player resources (for marines will be team resources) int GetPlayerResources(const edict_t* Player); diff --git a/main/source/mod/AIPlayers/AvHAITactical.cpp b/main/source/mod/AIPlayers/AvHAITactical.cpp index 8ad716f3..2a261c5a 100644 --- a/main/source/mod/AIPlayers/AvHAITactical.cpp +++ b/main/source/mod/AIPlayers/AvHAITactical.cpp @@ -232,7 +232,7 @@ AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer if (it.second.StructureType & Filter->DeployableTypes) { - if (!UTIL_PointIsDirectlyReachable(UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL), pBot->Edict->v.origin, it.second.Location)) { continue; } + if (!UTIL_PointIsDirectlyReachable(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, it.second.Location)) { continue; } float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location); @@ -255,7 +255,7 @@ AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer if (it.second.StructureType & Filter->DeployableTypes) { - if (!UTIL_PointIsDirectlyReachable(UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL), pBot->Edict->v.origin, it.second.Location)) { continue; } + if (!UTIL_PointIsDirectlyReachable(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, it.second.Location)) { continue; } float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location); @@ -338,7 +338,7 @@ Vector AITAC_GetFloorLocationForHive(const AvHAIHiveDefinition* Hive) FOR_ALL_ENTITIES(kesTeamStart, AvHTeamStartEntity*) if (NearestNavigableLoc == ZERO_VECTOR) { - NearestNavigableLoc = FindClosestNavigablePointToDestination(MARINE_REGULAR_NAV_PROFILE, theEntity->pev->origin, HiveFloorLoc, UTIL_MetresToGoldSrcUnits(10.0f)); + NearestNavigableLoc = FindClosestNavigablePointToDestination(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], theEntity->pev->origin, HiveFloorLoc, UTIL_MetresToGoldSrcUnits(10.0f)); } END_FOR_ALL_ENTITIES(kesTeamStart); @@ -493,9 +493,9 @@ void AITAC_RefreshResourceNodes() ResourceNodes[NumTotalResNodes].Location = theEntity->pev->origin; ResourceNodes[NumTotalResNodes].ReachabilityFlags = AI_REACHABILITY_NONE; - bool bIsReachableMarine = UTIL_PointIsReachable(MARINE_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResourceNodes[NumTotalResNodes].Location, max_player_use_reach); - bool bIsReachableSkulk = UTIL_PointIsReachable(SKULK_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResourceNodes[NumTotalResNodes].Location, max_player_use_reach); - bool bIsReachableOnos = UTIL_PointIsReachable(ONOS_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResourceNodes[NumTotalResNodes].Location, max_player_use_reach); + bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResourceNodes[NumTotalResNodes].Location, max_player_use_reach); + bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResourceNodes[NumTotalResNodes].Location, max_player_use_reach); + bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResourceNodes[NumTotalResNodes].Location, max_player_use_reach); if (bIsReachableMarine) { @@ -861,11 +861,11 @@ void AITAC_UpdateMarineItem(CBaseEntity* Item, AvHAIDeployableItemType ItemType) } else { - MarineDroppedItemMap[EntIndex].bOnNavMesh = UTIL_PointIsOnNavmesh(MARINE_REGULAR_NAV_PROFILE, ItemEdict->v.origin, Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach)); + MarineDroppedItemMap[EntIndex].bOnNavMesh = UTIL_PointIsOnNavmesh(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], ItemEdict->v.origin, Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach)); if (MarineDroppedItemMap[EntIndex].bOnNavMesh) { - MarineDroppedItemMap[EntIndex].bIsReachableMarine = UTIL_PointIsReachable(MARINE_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ItemEdict->v.origin, max_player_use_reach); + MarineDroppedItemMap[EntIndex].bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ItemEdict->v.origin, max_player_use_reach); } else { @@ -937,7 +937,7 @@ void AITAC_UpdateBuildableStructure(CBaseEntity* Structure) if (bShouldCollide) { - unsigned int area = UTIL_GetAreaForObstruction(StructureType); + unsigned int area = UTIL_GetAreaForObstruction(StructureType, BuildingEdict); float Radius = UTIL_GetStructureRadiusForObstruction(StructureType); UTIL_AddTemporaryObstacles(UTIL_GetCentreOfEntity(BuildingMap[EntIndex].edict), Radius, 100.0f, area, BuildingMap[EntIndex].ObstacleRefs); } @@ -953,12 +953,12 @@ void AITAC_UpdateBuildableStructure(CBaseEntity* Structure) if (vIsZero(BuildingMap[EntIndex].Location) || !vEquals(BaseBuildable->pev->origin, BuildingMap[EntIndex].Location, 5.0f)) { - bool bIsOnNavMesh = UTIL_PointIsOnNavmesh(MARINE_REGULAR_NAV_PROFILE, UTIL_GetEntityGroundLocation(BuildingEdict), Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach)); + bool bIsOnNavMesh = UTIL_PointIsOnNavmesh(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], UTIL_GetEntityGroundLocation(BuildingEdict), Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach)); if (bIsOnNavMesh) { - bool bIsReachableMarine = UTIL_PointIsReachable(MARINE_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach); - bool bIsReachableSkulk = UTIL_PointIsReachable(SKULK_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach); - bool bIsReachableOnos = UTIL_PointIsReachable(ONOS_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach); + bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach); + bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach); + bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(BuildingEdict), max_player_use_reach); if (bIsReachableMarine) { @@ -1237,10 +1237,15 @@ AvHAIDeployableStructureType UTIL_IUSER3ToStructureType(const int inIUSER3) } -unsigned char UTIL_GetAreaForObstruction(AvHAIDeployableStructureType StructureType) +unsigned char UTIL_GetAreaForObstruction(AvHAIDeployableStructureType StructureType, const edict_t* BuildingEdict) { if (StructureType == STRUCTURE_NONE) { return DT_TILECACHE_NULL_AREA; } + AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber(); + AvHTeamNumber TeamB = GetGameRules()->GetTeamBNumber(); + + unsigned char StructureArea = (BuildingEdict->v.team == TeamA) ? DT_TILECACHE_TEAM1STRUCTURE_AREA : DT_TILECACHE_TEAM2STRUCTURE_AREA; + switch (StructureType) { case STRUCTURE_MARINE_RESTOWER: @@ -1248,10 +1253,9 @@ unsigned char UTIL_GetAreaForObstruction(AvHAIDeployableStructureType StructureT case STRUCTURE_MARINE_ARMOURY: case STRUCTURE_MARINE_ADVARMOURY: case STRUCTURE_MARINE_OBSERVATORY: - return DT_TILECACHE_MSTRUCTURE_AREA; case STRUCTURE_ALIEN_RESTOWER: case STRUCTURE_ALIEN_HIVE: - return DT_TILECACHE_ASTRUCTURE_AREA; + return StructureArea; default: return DT_TILECACHE_BLOCKED_AREA; } @@ -1342,9 +1346,7 @@ bool UTIL_IsBuildableStructureStillReachable(AvHAIPlayer* pBot, const edict_t* S if (!StructureRef) { return false; } - int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - - return (StructureRef->ReachabilityFlags & UTIL_GetReachabilityFlagForProfile(MoveProfile)) != 0; + return (StructureRef->ReachabilityFlags & pBot->BotNavInfo.NavProfile.ReachabilityFlag) != 0; } bool UTIL_IsDroppedItemStillReachable(AvHAIPlayer* pBot, const edict_t* Item) @@ -1759,7 +1761,7 @@ Vector UTIL_GetNextMinePosition(edict_t* StructureToMine) } } - Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInDonut(MARINE_REGULAR_NAV_PROFILE, StructureToMine->v.origin, Size, Size + 16.0f); + Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInDonut(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], StructureToMine->v.origin, Size, Size + 16.0f); return BuildLocation; } diff --git a/main/source/mod/AIPlayers/AvHAITactical.h b/main/source/mod/AIPlayers/AvHAITactical.h index 3872b75b..739ea1cc 100644 --- a/main/source/mod/AIPlayers/AvHAITactical.h +++ b/main/source/mod/AIPlayers/AvHAITactical.h @@ -79,7 +79,7 @@ AvHAIDeployableStructureType UTIL_IUSER3ToStructureType(const int inIUSER3); bool UTIL_ShouldStructureCollide(AvHAIDeployableStructureType StructureType); float UTIL_GetStructureRadiusForObstruction(AvHAIDeployableStructureType StructureType); -unsigned char UTIL_GetAreaForObstruction(AvHAIDeployableStructureType StructureType); +unsigned char UTIL_GetAreaForObstruction(AvHAIDeployableStructureType StructureType, const edict_t* BuildingEdict); bool UTIL_IsStructureElectrified(edict_t* Structure); bool UTIL_StructureIsFullyBuilt(edict_t* Structure); diff --git a/main/source/mod/AIPlayers/AvHAITask.cpp b/main/source/mod/AIPlayers/AvHAITask.cpp index f5e69753..589cdada 100644 --- a/main/source/mod/AIPlayers/AvHAITask.cpp +++ b/main/source/mod/AIPlayers/AvHAITask.cpp @@ -385,14 +385,14 @@ bool AITASK_IsWeldTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) if (IsEdictPlayer(Task->TaskTarget)) { - if (!IsPlayerMarine(Task->TaskTarget) || !IsPlayerActiveInGame(Task->TaskTarget)) { return false; } + if (Task->TaskTarget->v.team != pBot->Edict->v.team || !IsPlayerMarine(Task->TaskTarget) || !IsPlayerActiveInGame(Task->TaskTarget)) { return false; } return (Task->TaskTarget->v.armorvalue < GetPlayerMaxArmour(Task->TaskTarget)); } else { if (IsEdictStructure(Task->TaskTarget)) { - if (!UTIL_IsBuildableStructureStillReachable(pBot, Task->TaskTarget)) { return false; } + if (Task->TaskTarget->v.team != pBot->Edict->v.team || !UTIL_IsBuildableStructureStillReachable(pBot, Task->TaskTarget)) { return false; } return (Task->TaskTarget->v.health < Task->TaskTarget->v.max_health); } @@ -1064,7 +1064,7 @@ void BotProgressMineStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) if (Task->BuildAttempts > 3) { float Size = fmaxf(Task->TaskTarget->v.size.x, Task->TaskTarget->v.size.y); - Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BUILDING_REGULAR_NAV_PROFILE, Task->TaskTarget->v.origin, Size + 8.0f); + Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], Task->TaskTarget->v.origin, Size + 8.0f); } else { @@ -1318,7 +1318,7 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) if (Task->TaskLocation != g_vecZero) { - dtPolyRef Poly = UTIL_GetNavAreaAtLocation(BUILDING_REGULAR_NAV_PROFILE, Task->TaskLocation); + dtPolyRef Poly = UTIL_GetNavAreaAtLocation(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], Task->TaskLocation); if (Poly != SAMPLE_POLYAREA_GROUND) { @@ -1332,7 +1332,7 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) Vector TargetLocation = (ReinforcedStructure == STRUCTURE_ALIEN_HIVE) ? UTIL_GetFloorUnderEntity(Task->TaskTarget) : Task->TaskTarget->v.origin; - Vector BuildLocation = FindClosestNavigablePointToDestination(MARINE_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), TargetLocation, UTIL_MetresToGoldSrcUnits(50.0f)); + Vector BuildLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), TargetLocation, UTIL_MetresToGoldSrcUnits(50.0f)); if (BuildLocation != g_vecZero) { @@ -1340,7 +1340,7 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) float MaxDist = fmaxf(UTIL_MetresToGoldSrcUnits(1.0f), (UTIL_MetresToGoldSrcUnits(5.0f) - currDist)); - Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(GORGE_BUILD_NAV_PROFILE, BuildLocation, MaxDist); + Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], BuildLocation, MaxDist); } if (vIsZero(Task->TaskLocation)) { return; } @@ -1640,11 +1640,11 @@ void BotProgressEvolveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) { if ((gpGlobals->time - Task->TaskStartedTime) > 1.0f) { - Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BUILDING_REGULAR_NAV_PROFILE, pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); + Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); if (vIsZero(Task->TaskLocation)) { - Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(GORGE_REGULAR_NAV_PROFILE, pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); + Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); } Task->TaskStartedTime = 0.0f; @@ -1675,14 +1675,14 @@ void BotProgressEvolveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) } else { - if (vDist2DSq(pBot->Edict->v.origin, UTIL_GetEntityGroundLocation(Task->TaskTarget)) > sqrf(UTIL_MetresToGoldSrcUnits(10.0f)) || UTIL_GetNavAreaAtLocation(GORGE_BUILD_NAV_PROFILE, pBot->Edict->v.origin) != SAMPLE_POLYAREA_GROUND) + if (vDist2DSq(pBot->Edict->v.origin, UTIL_GetEntityGroundLocation(Task->TaskTarget)) > sqrf(UTIL_MetresToGoldSrcUnits(10.0f)) || UTIL_GetNavAreaAtLocation(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], pBot->Edict->v.origin) != SAMPLE_POLYAREA_GROUND) { MoveTo(pBot, UTIL_GetEntityGroundLocation(Task->TaskTarget), MOVESTYLE_NORMAL); return; } else { - Task->TaskLocation = FindClosestNavigablePointToDestination(GORGE_BUILD_NAV_PROFILE, pBot->Edict->v.origin, UTIL_GetEntityGroundLocation(Task->TaskTarget), UTIL_MetresToGoldSrcUnits(10.0f)); + Task->TaskLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], pBot->Edict->v.origin, UTIL_GetEntityGroundLocation(Task->TaskTarget), UTIL_MetresToGoldSrcUnits(10.0f)); if (vIsZero(Task->TaskLocation)) { @@ -1691,7 +1691,7 @@ void BotProgressEvolveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) if (Task->TaskLocation != g_vecZero) { - Vector FinalEvolveLoc = UTIL_GetRandomPointOnNavmeshInRadius(GORGE_BUILD_NAV_PROFILE, Task->TaskLocation, UTIL_MetresToGoldSrcUnits(5.0f)); + Vector FinalEvolveLoc = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], Task->TaskLocation, UTIL_MetresToGoldSrcUnits(5.0f)); if (FinalEvolveLoc != g_vecZero) { @@ -1777,7 +1777,7 @@ void AlienProgressBuildHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) if (Task->bIsWaitingForBuildLink) { - Task->TaskLocation = FindClosestNavigablePointToDestination(GORGE_REGULAR_NAV_PROFILE, pBot->Edict->v.origin, Hive->FloorLocation, UTIL_MetresToGoldSrcUnits(7.5f)); + Task->TaskLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], pBot->Edict->v.origin, Hive->FloorLocation, UTIL_MetresToGoldSrcUnits(7.5f)); if (vIsZero(Task->TaskLocation)) { @@ -1789,7 +1789,7 @@ void AlienProgressBuildHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) float MaxDist = (UTIL_MetresToGoldSrcUnits(7.5f) - Dist); - Vector AltLocation = UTIL_GetRandomPointOnNavmeshInRadius(GORGE_REGULAR_NAV_PROFILE, Task->TaskLocation, MaxDist); + Vector AltLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], Task->TaskLocation, MaxDist); if (AltLocation != g_vecZero) { @@ -1899,18 +1899,18 @@ void AlienProgressBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) if (Task->bIsWaitingForBuildLink) { - Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(GORGE_BUILD_NAV_PROFILE, Task->TaskLocation, UTIL_MetresToGoldSrcUnits(2.0f)); + Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], Task->TaskLocation, UTIL_MetresToGoldSrcUnits(2.0f)); Task->bIsWaitingForBuildLink = false; } // If we are building a chamber if (Task->StructureType != STRUCTURE_ALIEN_RESTOWER) { - dtPolyRef Poly = UTIL_GetNavAreaAtLocation(BUILDING_REGULAR_NAV_PROFILE, Task->TaskLocation); + dtPolyRef Poly = UTIL_GetNavAreaAtLocation(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], Task->TaskLocation); if (Poly != SAMPLE_POLYAREA_GROUND) { - Vector NewLocation = UTIL_GetRandomPointOnNavmeshInRadius(BUILDING_REGULAR_NAV_PROFILE, Task->TaskLocation, UTIL_MetresToGoldSrcUnits(2.0f)); + Vector NewLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE], Task->TaskLocation, UTIL_MetresToGoldSrcUnits(2.0f)); if (NewLocation != g_vecZero) { @@ -2416,7 +2416,7 @@ void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation) } else { - pBot->GuardInfo.GuardLookLocation = UTIL_GetRandomPointOnNavmeshInRadius(SKULK_REGULAR_NAV_PROFILE, pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); + pBot->GuardInfo.GuardLookLocation = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); pBot->GuardInfo.GuardLookLocation.z = pBot->CurrentEyePosition.z; } @@ -2425,7 +2425,7 @@ void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation) Vector NewMoveCentre = GuardLocation - (LookDir * UTIL_MetresToGoldSrcUnits(2.0f)); - Vector NewMoveLoc = UTIL_GetRandomPointOnNavmeshInRadius(MARINE_REGULAR_NAV_PROFILE, NewMoveCentre, UTIL_MetresToGoldSrcUnits(2.0f)); + Vector NewMoveLoc = UTIL_GetRandomPointOnNavmeshInRadius(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], NewMoveCentre, UTIL_MetresToGoldSrcUnits(2.0f)); if (NewMoveLoc != g_vecZero) { @@ -2471,7 +2471,7 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat bool bEnemyIsAlien = GetGameRules()->GetTeam(EnemyTeam)->GetTeamType() == AVH_CLASS_TYPE_ALIEN; - int MoveProfileIndex = (bEnemyIsAlien) ? SKULK_REGULAR_NAV_PROFILE : MARINE_REGULAR_NAV_PROFILE; + const nav_profile NavProfile = (bEnemyIsAlien) ? BaseNavProfiles[SKULK_BASE_NAV_PROFILE] : BaseNavProfiles[MARINE_BASE_NAV_PROFILE]; bot_path_node path[MAX_AI_PATH_SIZE]; int pathSize = 0; @@ -2485,7 +2485,7 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat if (UTIL_QuickTrace(pEdict, GuardLocation + Vector(0.0f, 0.0f, 10.0f), Hive->Location) || vDist2DSq(GuardLocation, Hive->Location) < sqrf(UTIL_MetresToGoldSrcUnits(10.0f))) { continue; } - dtStatus SearchResult = FindPathClosestToPoint(MoveProfileIndex, Hive->FloorLocation, GuardLocation, path, &pathSize, 500.0f); + dtStatus SearchResult = FindPathClosestToPoint(NavProfile, Hive->FloorLocation, GuardLocation, path, &pathSize, 500.0f); if (dtStatusSucceed(SearchResult)) { @@ -2498,7 +2498,7 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat } } - dtStatus SearchResult = FindPathClosestToPoint(MoveProfileIndex, AITAC_GetTeamStartingLocation(EnemyTeam), GuardLocation, path, &pathSize, 500.0f); + dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(EnemyTeam), GuardLocation, path, &pathSize, 500.0f); if (dtStatusSucceed(SearchResult)) { @@ -2512,7 +2512,7 @@ void AITASK_GenerateGuardWatchPoints(AvHAIPlayer* pBot, const Vector& GuardLocat if (vDist2DSq(GuardLocation, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam())) > sqrf(UTIL_MetresToGoldSrcUnits(15.0f))) { - dtStatus SearchResult = FindPathClosestToPoint(MoveProfileIndex, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), GuardLocation, path, &pathSize, 500.0f); + dtStatus SearchResult = FindPathClosestToPoint(NavProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), GuardLocation, path, &pathSize, 500.0f); if (dtStatusSucceed(SearchResult)) { @@ -2658,6 +2658,7 @@ void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Targe Task->TaskTarget = Target; Task->TaskType = TASK_WELD; Task->bTaskIsUrgent = bIsUrgent; + Task->TaskLength = 0.0f; if (IsEdictPlayer(Target) || IsEdictStructure(Target)) { return; } @@ -2668,9 +2669,7 @@ void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Targe TargetLocation = Task->TaskTarget->v.origin; } - int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - - Vector TaskLocation = FindClosestNavigablePointToDestination(MoveProfile, pBot->Edict->v.origin, TargetLocation, UTIL_MetresToGoldSrcUnits(5.0f)); + Vector TaskLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, TargetLocation, UTIL_MetresToGoldSrcUnits(5.0f)); if (vIsZero(TaskLocation)) { @@ -2709,10 +2708,8 @@ void AITASK_SetAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Tar return; } - int BotProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - // Get as close as possible to the target - Vector AttackLocation = FindClosestNavigablePointToDestination(BotProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(Target), UTIL_MetresToGoldSrcUnits(20.0f)); + Vector AttackLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(Target), UTIL_MetresToGoldSrcUnits(20.0f)); if (AttackLocation != g_vecZero) { @@ -2736,10 +2733,8 @@ void AITASK_SetMoveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const Vector L if (vIsZero(Location)) { return; } - int BotProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - // Get as close as possible to desired location - Vector MoveLocation = FindClosestNavigablePointToDestination(BotProfile, pBot->CurrentFloorPosition, Location, UTIL_MetresToGoldSrcUnits(20.0f)); + Vector MoveLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, Location, UTIL_MetresToGoldSrcUnits(20.0f)); if (!vIsZero(MoveLocation)) { @@ -2760,12 +2755,12 @@ void AITASK_SetBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const AvHAIDe if (vIsZero(Location)) { return; } // Get as close as possible to desired location - Vector BuildLocation = FindClosestNavigablePointToDestination(GORGE_REGULAR_NAV_PROFILE, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), Location, UTIL_MetresToGoldSrcUnits(10.0f)); - BuildLocation = UTIL_ProjectPointToNavmesh(BuildLocation, BUILDING_REGULAR_NAV_PROFILE); + Vector BuildLocation = FindClosestNavigablePointToDestination(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), Location, UTIL_MetresToGoldSrcUnits(10.0f)); + BuildLocation = UTIL_ProjectPointToNavmesh(BuildLocation, BaseNavProfiles[STRUCTURE_BASE_NAV_PROFILE]); if (vIsZero(BuildLocation)) { - BuildLocation = FindClosestNavigablePointToDestination(UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL), pBot->CurrentFloorPosition, Location, UTIL_MetresToGoldSrcUnits(10.0f)); + BuildLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, Location, UTIL_MetresToGoldSrcUnits(10.0f)); } if (BuildLocation != g_vecZero) @@ -2804,10 +2799,8 @@ void AITASK_SetBuildTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Stru if (Task->TaskType == TASK_BUILD && Task->TaskTarget == StructureToBuild) { return; } - int BotProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - // Get as close as possible to desired location - Vector BuildLocation = FindClosestNavigablePointToDestination(BotProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(StructureToBuild), 80.0f); + Vector BuildLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(StructureToBuild), 80.0f); if (BuildLocation != g_vecZero) { @@ -2863,9 +2856,7 @@ void AITASK_SetDefendTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Tar Task->TaskTarget = Target; Task->bTaskIsUrgent = bIsUrgent; - int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - - Vector DefendPoint = FindClosestNavigablePointToDestination(MoveProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(Target), UTIL_MetresToGoldSrcUnits(10.0f)); + Vector DefendPoint = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UTIL_GetEntityGroundLocation(Target), UTIL_MetresToGoldSrcUnits(10.0f)); if (DefendPoint != g_vecZero) { @@ -2931,11 +2922,9 @@ void AITASK_SetUseTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target return; } - int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - Task->TaskType = TASK_USE; Task->TaskTarget = Target; - Task->TaskLocation = FindClosestNavigablePointToDestination(MoveProfile, pBot->CurrentFloorPosition, UTIL_ProjectPointToNavmesh(UTIL_GetCentreOfEntity(Target)), UTIL_MetresToGoldSrcUnits(10.0f)); + Task->TaskLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UTIL_ProjectPointToNavmesh(UTIL_GetCentreOfEntity(Target)), UTIL_MetresToGoldSrcUnits(10.0f)); Task->bTaskIsUrgent = bIsUrgent; Task->TaskLength = 10.0f; Task->TaskStartedTime = gpGlobals->time; @@ -2949,11 +2938,9 @@ void AITASK_SetUseTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Target return; } - int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - Task->TaskType = TASK_USE; Task->TaskTarget = Target; - Task->TaskLocation = FindClosestNavigablePointToDestination(MoveProfile, pBot->CurrentFloorPosition, UseLocation, UTIL_MetresToGoldSrcUnits(10.0f)); + Task->TaskLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UseLocation, UTIL_MetresToGoldSrcUnits(10.0f)); Task->bTaskIsUrgent = bIsUrgent; Task->TaskLength = 10.0f; Task->TaskStartedTime = gpGlobals->time; @@ -2967,11 +2954,9 @@ void AITASK_SetTouchTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Targ return; } - int MoveProfile = UTIL_GetMoveProfileForBot(pBot, MOVESTYLE_NORMAL); - Task->TaskType = TASK_TOUCH; Task->TaskTarget = Target; - Task->TaskLocation = FindClosestNavigablePointToDestination(MoveProfile, pBot->CurrentFloorPosition, UTIL_ProjectPointToNavmesh(UTIL_GetCentreOfEntity(Target)), UTIL_MetresToGoldSrcUnits(10.0f)); + Task->TaskLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, UTIL_ProjectPointToNavmesh(UTIL_GetCentreOfEntity(Target)), UTIL_MetresToGoldSrcUnits(10.0f)); Task->bTaskIsUrgent = bIsUrgent; } diff --git a/main/source/mod/AIPlayers/AvHAIWeaponHelper.cpp b/main/source/mod/AIPlayers/AvHAIWeaponHelper.cpp index 70b98523..202151e2 100644 --- a/main/source/mod/AIPlayers/AvHAIWeaponHelper.cpp +++ b/main/source/mod/AIPlayers/AvHAIWeaponHelper.cpp @@ -164,7 +164,7 @@ void InterruptReload(AvHAIPlayer* pBot) AvHAIWeapon UTIL_GetBotPrimaryWeapon(const AvHAIPlayer* pBot) { - AvHBasePlayerWeapon* Weapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[0]); + AvHBasePlayerWeapon* Weapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[1]); if (Weapon) { @@ -205,7 +205,7 @@ AvHAIWeapon GetBotMarineSecondaryWeapon(const AvHAIPlayer* pBot) int BotGetPrimaryWeaponMaxAmmoReserve(AvHAIPlayer* pBot) { - AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[0]); + AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[1]); if (theBasePlayerWeapon) { @@ -217,7 +217,7 @@ int BotGetPrimaryWeaponMaxAmmoReserve(AvHAIPlayer* pBot) int BotGetPrimaryWeaponAmmoReserve(AvHAIPlayer* pBot) { - AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[0]); + AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[1]); if (theBasePlayerWeapon) { @@ -229,7 +229,7 @@ int BotGetPrimaryWeaponAmmoReserve(AvHAIPlayer* pBot) int BotGetSecondaryWeaponAmmoReserve(AvHAIPlayer* pBot) { - AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[1]); + AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[2]); if (theBasePlayerWeapon) { @@ -241,7 +241,7 @@ int BotGetSecondaryWeaponAmmoReserve(AvHAIPlayer* pBot) int BotGetPrimaryWeaponClipAmmo(const AvHAIPlayer* pBot) { - AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[0]); + AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[1]); if (theBasePlayerWeapon) { @@ -253,7 +253,7 @@ int BotGetPrimaryWeaponClipAmmo(const AvHAIPlayer* pBot) int BotGetSecondaryWeaponClipAmmo(const AvHAIPlayer* pBot) { - AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[1]); + AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[2]); if (theBasePlayerWeapon) { @@ -265,7 +265,7 @@ int BotGetSecondaryWeaponClipAmmo(const AvHAIPlayer* pBot) int BotGetPrimaryWeaponMaxClipSize(const AvHAIPlayer* pBot) { - AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[0]); + AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[1]); if (theBasePlayerWeapon) { @@ -277,7 +277,7 @@ int BotGetPrimaryWeaponMaxClipSize(const AvHAIPlayer* pBot) int BotGetSecondaryWeaponMaxClipSize(const AvHAIPlayer* pBot) { - AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[1]); + AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[2]); if (theBasePlayerWeapon) { @@ -289,7 +289,7 @@ int BotGetSecondaryWeaponMaxClipSize(const AvHAIPlayer* pBot) int BotGetSecondaryWeaponMaxAmmoReserve(AvHAIPlayer* pBot) { - AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[1]); + AvHBasePlayerWeapon* theBasePlayerWeapon = dynamic_cast(pBot->Player->m_rgpPlayerItems[2]); if (theBasePlayerWeapon) { @@ -326,19 +326,19 @@ float GetMaxIdealWeaponRange(const AvHAIWeapon Weapon) case WEAPON_SKULK_XENOCIDE: return UTIL_MetresToGoldSrcUnits(5.0f); case WEAPON_ONOS_GORE: - return kClawsRange; + return BALANCE_VAR(kClawsRange); case WEAPON_ONOS_DEVOUR: - return kDevourRange; + return BALANCE_VAR(kDevourRange); case WEAPON_FADE_SWIPE: - return kSwipeRange; + return BALANCE_VAR(kSwipeRange); case WEAPON_SKULK_BITE: - return kBiteRange; + return BALANCE_VAR(kBiteRange); case WEAPON_LERK_BITE: - return kBite2Range; + return BALANCE_VAR(kBite2Range); case WEAPON_GORGE_HEALINGSPRAY: - return kHealingSprayRange; + return BALANCE_VAR(kHealingSprayRange); case WEAPON_MARINE_WELDER: - return kWelderRange; + return BALANCE_VAR(kWelderRange); default: return max_player_use_reach; } @@ -428,7 +428,7 @@ Vector UTIL_GetGrenadeThrowTarget(edict_t* Player, const Vector TargetLocation, bot_path_node CheckPath[MAX_AI_PATH_SIZE]; int PathSize = 0; - dtStatus Status = FindPathClosestToPoint(ALL_NAV_PROFILE, Player->v.origin, TargetLocation, CheckPath, &PathSize, ExplosionRadius); + dtStatus Status = FindPathClosestToPoint(BaseNavProfiles[ALL_NAV_PROFILE], Player->v.origin, TargetLocation, CheckPath, &PathSize, ExplosionRadius); if (dtStatusSucceed(Status)) {