From 451810e07b4e2e2da189c8a0d2134e5e00b648b0 Mon Sep 17 00:00:00 2001 From: RGreenlees Date: Thu, 8 Feb 2024 23:29:57 +0000 Subject: [PATCH] Bug fixing with navigation --- main/source/detour/DetourTileCache.cpp | 10 ++- main/source/detour/Include/DetourTileCache.h | 2 +- main/source/mod/AIPlayers/AvHAICommander.cpp | 20 +++++- main/source/mod/AIPlayers/AvHAIConstants.h | 5 +- main/source/mod/AIPlayers/AvHAINavigation.cpp | 46 +++++++++---- main/source/mod/AIPlayers/AvHAINavigation.h | 2 +- main/source/mod/AIPlayers/AvHAIPlayer.cpp | 69 +++++++++++++++++-- .../mod/AIPlayers/AvHAIPlayerManager.cpp | 7 +- main/source/mod/AIPlayers/AvHAITactical.cpp | 36 +++++++--- main/source/mod/AIPlayers/AvHAITask.cpp | 4 +- main/source/mod/AvHConsoleCommands.cpp | 11 +++ 11 files changed, 175 insertions(+), 37 deletions(-) diff --git a/main/source/detour/DetourTileCache.cpp b/main/source/detour/DetourTileCache.cpp index 6f8e99fb..7e19ebfe 100644 --- a/main/source/detour/DetourTileCache.cpp +++ b/main/source/detour/DetourTileCache.cpp @@ -154,6 +154,7 @@ dtStatus dtTileCache::init(const dtTileCacheParams* params, { m_offMeshConnections[i].salt = 1; m_offMeshConnections[i].next = m_nextFreeOffMeshConnection; + m_offMeshConnections[i].userId = i; m_nextFreeOffMeshConnection = &m_offMeshConnections[i]; } @@ -405,7 +406,9 @@ dtStatus dtTileCache::addOffMeshConnection(const float* spos, const float* epos, return DT_FAILURE | DT_OUT_OF_MEMORY; unsigned short salt = con->salt; + unsigned int userId = con->userId; memset(con, 0, sizeof(dtOffMeshConnection)); + con->userId = userId; con->salt = salt; con->state = DT_OFFMESH_NEW; dtVcopy(&con->pos[0], spos); @@ -420,8 +423,6 @@ dtStatus dtTileCache::addOffMeshConnection(const float* spos, const float* epos, req->action = REQUEST_OFFMESH_ADD; req->ref = getOffMeshRef(con); - con->userId = req->ref; - if (result) *result = req->ref; @@ -676,6 +677,7 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh, if ((int)idx >= m_params.maxOffMeshConnections) continue; dtOffMeshConnection* con = &m_offMeshConnections[idx]; + con->userId = idx; unsigned int salt = decodeOffMeshIdSalt(req->ref); if (con->salt != salt) continue; @@ -749,6 +751,10 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh, m_update[m_nupdate++] = TileRef; } } + else if (req->action == REQUEST_OFFMESH_REFRESH) + { + con->state = DT_OFFMESH_DIRTY; + } } m_nOffMeshReqs = 0; diff --git a/main/source/detour/Include/DetourTileCache.h b/main/source/detour/Include/DetourTileCache.h index f69dc2fd..5a35b34d 100644 --- a/main/source/detour/Include/DetourTileCache.h +++ b/main/source/detour/Include/DetourTileCache.h @@ -306,7 +306,7 @@ private: OffMeshRequest m_OffMeshReqs[MAX_REQUESTS]; int m_nOffMeshReqs; - static const int MAX_UPDATE = 64; + static const int MAX_UPDATE = 256; dtCompressedTileRef m_update[MAX_UPDATE]; int m_nupdate; }; diff --git a/main/source/mod/AIPlayers/AvHAICommander.cpp b/main/source/mod/AIPlayers/AvHAICommander.cpp index dbea9093..18fe3edc 100644 --- a/main/source/mod/AIPlayers/AvHAICommander.cpp +++ b/main/source/mod/AIPlayers/AvHAICommander.cpp @@ -16,11 +16,18 @@ bool AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureTyp { if (vIsZero(Location)) { return false; } + nav_profile WelderProfile = GetBaseNavProfile(MARINE_BASE_NAV_PROFILE); + WelderProfile.Filters.addIncludeFlags(SAMPLE_POLYFLAGS_WELD); + + // Don't allow the commander to place a structure somewhere unreachable to marines + if (!UTIL_PointIsReachable(WelderProfile, AITAC_GetTeamStartingLocation(pBot->Player->GetTeam()), Location, max_player_use_reach)) { return false; } + AvHMessageID StructureID = UTIL_StructureTypeToImpulseCommand(StructureToDeploy); Vector BuildLocation = Location; BuildLocation.z += 4.0f; + // This would be rejected if a human was trying to build here, so don't let the bot do it if (!AvHSHUGetIsSiteValidForBuild(StructureID, &BuildLocation)) { return false; } string theErrorMessage; @@ -358,6 +365,8 @@ bool AICOMM_IsOrderStillValid(AvHAIPlayer* pBot, ai_commander_order* Order) break; case ORDERPURPOSE_SECURE_RESNODE: { + if (!AICOMM_ShouldCommanderPrioritiseNodes(pBot)) { return false; } + const AvHAIResourceNode* ResNode = AITAC_GetResourceNodeFromEdict(Order->OrderTarget); if (!ResNode) { return false; } @@ -408,6 +417,8 @@ bool AICOMM_ShouldCommanderPrioritiseNodes(AvHAIPlayer* pBot) int NumEligibleNodes = 0; int NumFreeNodes = 0; + + // First get ours and the enemy's ownership of all eligible nodes (we can reach them, and they're in the enemy base) vector AllNodes = AITAC_GetAllReachableResourceNodes(BotTeam); @@ -428,11 +439,13 @@ bool AICOMM_ShouldCommanderPrioritiseNodes(AvHAIPlayer* pBot) if (ThisNode->OwningTeam == BotTeam) { NumOwnedNodes++; } } + int NumDesiredNodes = imini(4, (int)ceilf((float)NumEligibleNodes * 0.5f)); + int NumNodesLeft = NumEligibleNodes - NumOwnedNodes; if (NumNodesLeft == 0) { return false; } - return NumOwnedNodes < 3 || NumFreeNodes > 3; + return NumOwnedNodes < NumDesiredNodes || NumFreeNodes > 1; } @@ -1076,6 +1089,11 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot) { Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInDonutIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), BaseArmoury->Location, UTIL_MetresToGoldSrcUnits(3.0f), UTIL_MetresToGoldSrcUnits(5.0f)); + if (vIsZero(BuildLocation)) + { + BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f)); + } + if (!vIsZero(BuildLocation)) { if (AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PROTOTYPELAB, BuildLocation)) diff --git a/main/source/mod/AIPlayers/AvHAIConstants.h b/main/source/mod/AIPlayers/AvHAIConstants.h index 317a570c..878319af 100644 --- a/main/source/mod/AIPlayers/AvHAIConstants.h +++ b/main/source/mod/AIPlayers/AvHAIConstants.h @@ -258,7 +258,7 @@ typedef struct _HIVE_DEFINITION_T AvHTeamNumber OwningTeam = TEAM_IND; // Which team owns this hive currently (TEAM_IND if empty) unsigned int TeamAReachabilityFlags = AI_REACHABILITY_NONE; // Who on team A can reach this node? unsigned int TeamBReachabilityFlags = AI_REACHABILITY_NONE; // Who on team B can reach this node? - + char HiveName[64]; } AvHAIHiveDefinition; // A nav profile combines a nav mesh reference (indexed into NavMeshes) and filters to determine how a bot should find paths @@ -542,6 +542,7 @@ typedef struct _AVH_AI_STUCK_TRACKER Vector LastBotPosition = g_vecZero; Vector MoveDestination = g_vecZero; float TotalStuckTime = 0.0f; // Total time the bot has spent stuck + bool bPathFollowFailed = false; } AvHAIPlayerStuckTracker; @@ -549,7 +550,7 @@ typedef struct _AVH_AI_STUCK_TRACKER typedef struct _NAV_STATUS { vector CurrentPath; // Bot's path nodes - vector::iterator CurrentPathPoint; + vector::iterator CurrentPathPoint = CurrentPath.end(); Vector TargetDestination = g_vecZero; // Desired destination Vector ActualMoveDestination = g_vecZero; // Actual destination on nav mesh diff --git a/main/source/mod/AIPlayers/AvHAINavigation.cpp b/main/source/mod/AIPlayers/AvHAINavigation.cpp index 99f24c2c..fe0d6267 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.cpp +++ b/main/source/mod/AIPlayers/AvHAINavigation.cpp @@ -1665,7 +1665,7 @@ dtStatus FindPathClosestToPoint(const nav_profile& NavProfile, const Vector From if (CurrFlags == SAMPLE_POLYFLAGS_WALLCLIMB || CurrFlags == SAMPLE_POLYFLAGS_LADDER) { - float NewRequiredZ = UTIL_FindZHeightForWallClimb(path.back().Location, NextPathNode.Location, head_hull); + float NewRequiredZ = UTIL_FindZHeightForWallClimb(NextPathNode.FromLocation, NextPathNode.Location, head_hull); //NextPathNode.requiredZ = fmaxf(NewRequiredZ, NextPathNode.Location.z); NextPathNode.requiredZ = NewRequiredZ; @@ -2003,6 +2003,8 @@ bool HasBotReachedPathPoint(const AvHAIPlayer* pBot) { if (!bIsAtFinalPathPoint) { + if (pBot->BotNavInfo.IsOnGround && fabsf(pEdict->v.origin.z - MoveTo.z) > 50.0f) { return false; } + Vector thisMoveDir = UTIL_GetVectorNormal2D(MoveTo - MoveFrom); Vector nextMoveDir = UTIL_GetVectorNormal2D(next(pBot->BotNavInfo.CurrentPathPoint)->Location - MoveTo); @@ -2019,7 +2021,7 @@ bool HasBotReachedPathPoint(const AvHAIPlayer* pBot) } else { - return (vDist2D(pEdict->v.origin, MoveTo) <= playerRadius && (pEdict->v.origin.z - MoveTo.z) < 50.0f && pBot->BotNavInfo.IsOnGround); + return (vDist2D(pEdict->v.origin, MoveTo) <= playerRadius && fabsf(pEdict->v.origin.z - MoveTo.z) < 50.0f && pBot->BotNavInfo.IsOnGround); } } case SAMPLE_POLYFLAGS_WALLCLIMB: @@ -5092,21 +5094,29 @@ bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination) void UpdateBotStuck(AvHAIPlayer* pBot) { - if (vIsZero(pBot->desiredMovementDir)) + if (vIsZero(pBot->desiredMovementDir) && !pBot->BotNavInfo.StuckInfo.bPathFollowFailed) { return; } - bool bIsFollowingPath = (pBot->BotNavInfo.CurrentPath.size() > 0 && pBot->BotNavInfo.CurrentPathPoint != pBot->BotNavInfo.CurrentPath.end()); - - bool bDist3D = pBot->BotNavInfo.NavProfile.bFlyingProfile || (bIsFollowingPath && (pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_LADDER || pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_WALLCLIMB)); - - float DistFromLastPoint = (bDist3D) ? vDist3DSq(pBot->Edict->v.origin, pBot->BotNavInfo.StuckInfo.LastBotPosition) : vDist2DSq(pBot->Edict->v.origin, pBot->BotNavInfo.StuckInfo.LastBotPosition); - - if (DistFromLastPoint >= sqrf(8.0f)) + if (!pBot->BotNavInfo.StuckInfo.bPathFollowFailed) { - pBot->BotNavInfo.StuckInfo.TotalStuckTime = 0.0f; - pBot->BotNavInfo.StuckInfo.LastBotPosition = pBot->Edict->v.origin; + + bool bIsFollowingPath = (pBot->BotNavInfo.CurrentPath.size() > 0 && pBot->BotNavInfo.CurrentPathPoint != pBot->BotNavInfo.CurrentPath.end()); + + bool bDist3D = pBot->BotNavInfo.NavProfile.bFlyingProfile || (bIsFollowingPath && (pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_LADDER || pBot->BotNavInfo.CurrentPathPoint->flag == SAMPLE_POLYFLAGS_WALLCLIMB)); + + float DistFromLastPoint = (bDist3D) ? vDist3DSq(pBot->Edict->v.origin, pBot->BotNavInfo.StuckInfo.LastBotPosition) : vDist2DSq(pBot->Edict->v.origin, pBot->BotNavInfo.StuckInfo.LastBotPosition); + + if (DistFromLastPoint >= sqrf(8.0f)) + { + pBot->BotNavInfo.StuckInfo.TotalStuckTime = 0.0f; + pBot->BotNavInfo.StuckInfo.LastBotPosition = pBot->Edict->v.origin; + } + else + { + pBot->BotNavInfo.StuckInfo.TotalStuckTime += AIMGR_GetBotDeltaTime(); + } } else { @@ -5115,6 +5125,12 @@ void UpdateBotStuck(AvHAIPlayer* pBot) if (pBot->BotNavInfo.StuckInfo.TotalStuckTime > 0.25f) { + if (pBot->BotNavInfo.StuckInfo.TotalStuckTime > 15.0f) + { + BotSuicide(pBot); + return; + } + BotJump(pBot); if (!IsPlayerSkulk(pBot->Edict)) { @@ -5425,6 +5441,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move if (dtStatusSucceed(PathFindingStatus)) { + pBot->BotNavInfo.StuckInfo.bPathFollowFailed = false; ClearBotStuckMovement(pBot); pBot->BotNavInfo.TotalStuckTime = 0.0f; BotNavInfo->PathDestination = Destination; @@ -5439,6 +5456,8 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move } else { + pBot->BotNavInfo.StuckInfo.bPathFollowFailed = true; + if (!vIsZero(BotNavInfo->LastNavMeshPosition)) { MoveDirectlyTo(pBot, BotNavInfo->LastNavMeshPosition); @@ -5870,10 +5889,13 @@ void BotFollowPath(AvHAIPlayer* pBot) if (IsBotOffPath(pBot)) { + pBot->BotNavInfo.StuckInfo.bPathFollowFailed = true; ClearBotPath(pBot); return; } + pBot->BotNavInfo.StuckInfo.bPathFollowFailed = false; + Vector MoveTo = BotNavInfo->CurrentPathPoint->Location; NewMove(pBot); diff --git a/main/source/mod/AIPlayers/AvHAINavigation.h b/main/source/mod/AIPlayers/AvHAINavigation.h index 9b0d94aa..4f2c594f 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.h +++ b/main/source/mod/AIPlayers/AvHAINavigation.h @@ -115,7 +115,7 @@ static const int NAVMESHSET_MAGIC = 'M' << 24 | 'S' << 16 | 'E' << 8 | 'T'; //'M static const int NAVMESHSET_VERSION = 1; static const int TILECACHESET_MAGIC = 'T' << 24 | 'S' << 16 | 'E' << 8 | 'T'; //'TSET', used to confirm the tile cache we're loading is compatible; -static const int TILECACHESET_VERSION = 1; +static const int TILECACHESET_VERSION = 2; static const float pExtents[3] = { 400.0f, 50.0f, 400.0f }; // Default extents (in GoldSrc units) to find the nearest spot on the nav mesh static const float pReachableExtents[3] = { max_ai_use_reach, max_ai_use_reach, max_ai_use_reach }; // Extents (in GoldSrc units) to determine if something is on the nav mesh diff --git a/main/source/mod/AIPlayers/AvHAIPlayer.cpp b/main/source/mod/AIPlayers/AvHAIPlayer.cpp index 2823defd..fd24d358 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayer.cpp +++ b/main/source/mod/AIPlayers/AvHAIPlayer.cpp @@ -3026,8 +3026,6 @@ void AIPlayerSetPrimaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) void AIPlayerSetMarineSweeperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) { - if (Task->TaskType == TASK_GUARD) { return; } - AvHTeamNumber BotTeam = pBot->Player->GetTeam(); Vector CommChairLocation = AITAC_GetCommChairLocation(BotTeam); @@ -3041,7 +3039,7 @@ void AIPlayerSetMarineSweeperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas StructureFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag; StructureFilter.ExcludeStatusFlags = (STRUCTURE_STATUS_RECYCLING | STRUCTURE_STATUS_COMPLETED); - AvHAIBuildableStructure* UnbuiltIP = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &StructureFilter); + AvHAIBuildableStructure* UnbuiltIP = AITAC_FindClosestDeployableToLocation(CommChairLocation, &StructureFilter); if (UnbuiltIP) { @@ -3049,6 +3047,49 @@ void AIPlayerSetMarineSweeperPrimaryTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas return; } + StructureFilter.DeployableTypes = SEARCH_ALL_STRUCTURES; + StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(15.0f); + + AvHAIBuildableStructure* UnbuiltStructure = AITAC_FindClosestDeployableToLocation(CommChairLocation, &StructureFilter); + + if (UnbuiltStructure) + { + AITASK_SetBuildTask(pBot, Task, UnbuiltStructure->edict, true); + return; + } + + DeployableSearchFilter AttackedStructureFilter; + AttackedStructureFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL; + AttackedStructureFilter.DeployableTeam = BotTeam; + AttackedStructureFilter.ReachabilityTeam = BotTeam; + AttackedStructureFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag; + AttackedStructureFilter.IncludeStatusFlags = STRUCTURE_STATUS_UNDERATTACK; + AttackedStructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; + AttackedStructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f); + AttackedStructureFilter.bConsiderPhaseDistance = true; + + AvHAIBuildableStructure* AttackedStructure = AITAC_FindClosestDeployableToLocation(CommChairLocation, &AttackedStructureFilter); + + if (AttackedStructure) + { + AITASK_SetDefendTask(pBot, Task, AttackedStructure->edict, true); + return; + } + + if (PlayerHasWeapon(pBot->Player, WEAPON_MARINE_WELDER)) + { + AttackedStructureFilter.IncludeStatusFlags = STRUCTURE_STATUS_DAMAGED; + + AvHAIBuildableStructure* AttackedStructure = AITAC_FindClosestDeployableToLocation(CommChairLocation, &AttackedStructureFilter); + + if (AttackedStructure) + { + AITASK_SetWeldTask(pBot, Task, AttackedStructure->edict, true); + return; + } + } + + StructureFilter.DeployableTypes = STRUCTURE_MARINE_PHASEGATE; StructureFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED; StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; @@ -3482,7 +3523,7 @@ void AIPlayerRequestOrder(AvHAIPlayer* pBot) void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) { // If we're building, finish that before doing anything else - if (Task->TaskType == TASK_BUILD && vDist2DSq(pBot->Edict->v.origin, Task->TaskTarget->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(3.0f))) + if (Task->TaskType == TASK_BUILD && (Task->StructureType == STRUCTURE_MARINE_INFANTRYPORTAL || vDist2DSq(pBot->Edict->v.origin, Task->TaskTarget->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(3.0f)))) { return; } @@ -3491,13 +3532,29 @@ void AIPlayerSetSecondaryMarineTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) // Find any nearby unbuilt structures DeployableSearchFilter UnbuiltFilter; - UnbuiltFilter.DeployableTypes = SEARCH_ALL_MARINE_STRUCTURES; + UnbuiltFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL; UnbuiltFilter.DeployableTeam = BotTeam; UnbuiltFilter.ReachabilityTeam = BotTeam; UnbuiltFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag; - UnbuiltFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING | STRUCTURE_STATUS_COMPLETED; + UnbuiltFilter.ExcludeStatusFlags = (STRUCTURE_STATUS_RECYCLING | STRUCTURE_STATUS_COMPLETED); UnbuiltFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f); + AvHAIBuildableStructure* UnbuiltIP = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &UnbuiltFilter); + + if (UnbuiltIP) + { + float ThisDist = vDist2D(UnbuiltIP->Location, pBot->Edict->v.origin); + int NumBuilders = AITAC_GetNumPlayersOfTeamInArea(BotTeam, UnbuiltIP->Location, ThisDist - 5.0f, false, pBot->Edict, AVH_USER3_COMMANDER_PLAYER); + + if (NumBuilders < 1) + { + AITASK_SetBuildTask(pBot, Task, UnbuiltIP->edict, true); + return; + } + } + + UnbuiltFilter.DeployableTypes = SEARCH_ALL_STRUCTURES; + vector BuildableStructures = AITAC_FindAllDeployables(pBot->Edict->v.origin, &UnbuiltFilter); AvHAIBuildableStructure* NearestStructure = nullptr; diff --git a/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp b/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp index 393db733..63c8e506 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp +++ b/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp @@ -36,7 +36,7 @@ AvHAIPlayer* DebugAIPlayer = nullptr; vector DebugPath; -string BotNames[MAX_PLAYERS] = { "MrRobot", +string BotNames[MAX_PLAYERS] = { "MrRobot", "Wall-E", "BeepBoop", "Robotnik", @@ -652,7 +652,7 @@ void AIMGR_UpdateAIPlayers() nav_profile NavProfile = GetBaseNavProfile(MARINE_BASE_NAV_PROFILE); NavProfile.Filters.addIncludeFlags(SAMPLE_POLYFLAGS_WELD); - dtStatus PathStatus = FindPathClosestToPoint(NavProfile, DebugVector1, DebugVector2, path, 100.0f); + dtStatus PathStatus = FindPathClosestToPoint(NavProfile, DebugVector1, DebugVector2, path, UTIL_MetresToGoldSrcUnits(10.0f)); if (dtStatusSucceed(PathStatus)) { @@ -828,6 +828,8 @@ void AIMGR_ResetRound() AIStartedTime = gpGlobals->time; } + LastAIPlayerCountUpdate = 0.0f; + AITAC_ClearMapAIData(); UTIL_PopulateDoors(); @@ -886,6 +888,7 @@ void AIMGR_NewMap() ActiveAIPlayers.clear(); AIStartedTime = gpGlobals->time; + LastAIPlayerCountUpdate = 0.0f; ALERT(at_console, "AI Manager New Map\n"); if (NavmeshLoaded()) diff --git a/main/source/mod/AIPlayers/AvHAITactical.cpp b/main/source/mod/AIPlayers/AvHAITactical.cpp index 474e2681..0fc3f296 100644 --- a/main/source/mod/AIPlayers/AvHAITactical.cpp +++ b/main/source/mod/AIPlayers/AvHAITactical.cpp @@ -18,6 +18,7 @@ #include "../AvHGamerules.h" #include "../AvHServerUtil.h" +#include "../AvHSharedUtil.h" #include "../AvHMarineEquipment.h" #include @@ -27,6 +28,7 @@ #include + vector ResourceNodes; vector Hives; @@ -638,14 +640,18 @@ Vector AITAC_GetFloorLocationForHive(const AvHAIHiveDefinition* Hive) Vector NearestNavigableLoc = ZERO_VECTOR; - FOR_ALL_ENTITIES(kesTeamStart, AvHTeamStartEntity*) - if (NearestNavigableLoc == ZERO_VECTOR) - { - NearestNavigableLoc = FindClosestNavigablePointToDestination(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], theEntity->pev->origin, HiveFloorLoc, UTIL_MetresToGoldSrcUnits(10.0f)); - } - END_FOR_ALL_ENTITIES(kesTeamStart); + nav_profile TestNavProfile = GetBaseNavProfile(MARINE_BASE_NAV_PROFILE); + TestNavProfile.Filters.addIncludeFlags(SAMPLE_POLYFLAGS_WELD); + TestNavProfile.ReachabilityFlag = AI_REACHABILITY_WELDER; - if (NearestNavigableLoc != ZERO_VECTOR) + FOR_ALL_ENTITIES(kwsTeamCommand, AvHCommandStation*) + if (vIsZero(NearestNavigableLoc)) + { + NearestNavigableLoc = FindClosestNavigablePointToDestination(TestNavProfile, theEntity->pev->origin, HiveFloorLoc, UTIL_MetresToGoldSrcUnits(10.0f)); + } + END_FOR_ALL_ENTITIES(kwsTeamCommand); + + if (!vIsZero(NearestNavigableLoc)) { return NearestNavigableLoc; } @@ -653,12 +659,15 @@ Vector AITAC_GetFloorLocationForHive(const AvHAIHiveDefinition* Hive) { return HiveFloorLoc; } + } void AITAC_PopulateHiveData() { Hives.clear(); + const AvHBaseInfoLocationListType& theInfoLocations = GetGameRules()->GetInfoLocations(); + FOR_ALL_ENTITIES(kesTeamHive, AvHHive*) AvHAIHiveDefinition NewHive; @@ -675,6 +684,17 @@ void AITAC_PopulateHiveData() NewHive.FloorLocation = UTIL_GetFloorUnderEntity(theEntity->edict()); // Some hives are suspended in the air, this is the floor location directly beneath it + string HiveName; + + string theLocationName; + if (AvHSHUGetNameOfLocation(GetGameRules()->GetInfoLocations(), NewHive.Location, theLocationName)) + { + HiveName = theLocationName; + } + + sprintf(NewHive.HiveName, HiveName.c_str(), "%s"); + + Hives.push_back(NewHive); END_FOR_ALL_ENTITIES(kesTeamHive) @@ -734,7 +754,7 @@ void AITAC_RefreshHiveData() it->NextFloorLocationCheck = gpGlobals->time + 1.0f; } - if (it->NextFloorLocationCheck > 0.0f && gpGlobals->time >= it->NextFloorLocationCheck) + if (gpGlobals->time >= it->NextFloorLocationCheck) { it->FloorLocation = AITAC_GetFloorLocationForHive(&(*it)); diff --git a/main/source/mod/AIPlayers/AvHAITask.cpp b/main/source/mod/AIPlayers/AvHAITask.cpp index c321dfbf..13a341b4 100644 --- a/main/source/mod/AIPlayers/AvHAITask.cpp +++ b/main/source/mod/AIPlayers/AvHAITask.cpp @@ -2629,7 +2629,7 @@ void MarineProgressCapResNodeTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) else { // If we're not at our destination yet, go there - if (vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation) > UTIL_MetresToGoldSrcUnits(5.0f)) + if (vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation) > sqrf(UTIL_MetresToGoldSrcUnits(5.0f))) { MoveTo(pBot, Task->TaskLocation, MOVESTYLE_NORMAL); return; @@ -2697,7 +2697,7 @@ void BotGuardLocation(AvHAIPlayer* pBot, const Vector GuardLocation) { if (IsPlayerLerk(pBot->Edict)) { - MoveTo(pBot, pBot->GuardInfo.GuardStandPosition, MOVESTYLE_HIDE); + MoveTo(pBot, pBot->GuardInfo.GuardStandPosition, MOVESTYLE_AMBUSH); } else { diff --git a/main/source/mod/AvHConsoleCommands.cpp b/main/source/mod/AvHConsoleCommands.cpp index 28605cac..0a229996 100644 --- a/main/source/mod/AvHConsoleCommands.cpp +++ b/main/source/mod/AvHConsoleCommands.cpp @@ -1542,6 +1542,17 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) theSuccess = true; } + else if (FStrEq(pcmd, "showhivefloors")) + { + vector AllHives = AITAC_GetAllHives(); + + for (auto it = AllHives.begin(); it != AllHives.end(); it++) + { + UTIL_DrawLine(INDEXENT(1), INDEXENT(1)->v.origin, (*it)->FloorLocation, 20.0f, 255, 255, 0); + } + + theSuccess = true; + } else if (FStrEq(pcmd, "testresearchavailable")) { AvHTeam* PlayerTeam = GetGameRules()->GetTeam(theAvHPlayer->GetTeam());