diff --git a/main/source/mod/AIPlayers/AvHAIConstants.h b/main/source/mod/AIPlayers/AvHAIConstants.h index a6d62e26..42eba7b5 100644 --- a/main/source/mod/AIPlayers/AvHAIConstants.h +++ b/main/source/mod/AIPlayers/AvHAIConstants.h @@ -80,22 +80,6 @@ typedef enum HIVE_TECH_MOVEMENT = 3 } HiveTechStatus; -// Data structure to hold information about each hive in the map -typedef struct _HIVE_DEFINITION_T -{ - AvHHive* HiveEntity = nullptr; - Vector Location = g_vecZero; // Origin of the hive - Vector FloorLocation = g_vecZero; // Some hives are suspended in the air, this is the floor location directly beneath it - HiveStatusType Status = HIVE_STATUS_UNBUILT; // Can be unbuilt, in progress, or fully built - AvHMessageID TechStatus = MESSAGE_NULL; // What tech (if any) is assigned to this hive right now - bool bIsUnderAttack = false; // Is the hive currently under attack? Becomes false if not taken damage for more than 10 seconds - int HiveResNodeIndex = -1; // Which resource node (indexes into ResourceNodes array) belongs to this hive? - unsigned int ObstacleRefs[8]; // When in progress or built, will place an obstacle so bots don't try to walk through it - float NextFloorLocationCheck = 0.0f; // When should the closest navigable point to the hive be calculated? Used to delay the check after a hive is built - AvHTeamNumber OwningTeam = TEAM_IND; - -} AvHAIHiveDefinition; - typedef enum _AI_REACHABILITY_STATUS { AI_REACHABILITY_NONE = 0, @@ -105,18 +89,6 @@ typedef enum _AI_REACHABILITY_STATUS AI_REACHABILITY_WELDER = 1u << 3, } AvHAIReachabilityStatus; -// Data structure used to track resource nodes in the map -typedef struct _RESOURCE_NODE -{ - AvHFuncResource* ResourceEntity = nullptr; // The func_resource edict reference - Vector Location = g_vecZero; // origin of the func_resource edict (not the tower itself) - bool bIsOccupied = false; // True if there is any resource tower on it - AvHTeamNumber OwningTeam = TEAM_IND; // The team that has currently capped this node (TEAM_IND if none) - edict_t* ActiveTowerEntity = nullptr; // Reference to the resource tower edict (if capped) - bool bIsBaseNode = false; // Is this a node in the marine base or active alien hive? - unsigned int ReachabilityFlags = AI_REACHABILITY_NONE; // Is this reachable by the bots? Checks for marine reachability only -} AvHAIResourceNode; - typedef enum { STRUCTURE_STATUS_NONE = 0, // No filters, all buildings will be returned @@ -193,6 +165,34 @@ typedef enum _STRUCTUREPURPOSE } StructurePurpose; +// Data structure used to track resource nodes in the map +typedef struct _RESOURCE_NODE +{ + AvHFuncResource* ResourceEntity = nullptr; // The func_resource edict reference + Vector Location = g_vecZero; // origin of the func_resource edict (not the tower itself) + bool bIsOccupied = false; // True if there is any resource tower on it + AvHTeamNumber OwningTeam = TEAM_IND; // The team that has currently capped this node (TEAM_IND if none) + edict_t* ActiveTowerEntity = nullptr; // Reference to the resource tower edict (if capped) + bool bIsBaseNode = false; // Is this a node in the marine base or active alien hive? + unsigned int ReachabilityFlags = AI_REACHABILITY_NONE; // Is this reachable by the bots? Checks for marine reachability only +} AvHAIResourceNode; + +// Data structure to hold information about each hive in the map +typedef struct _HIVE_DEFINITION_T +{ + AvHHive* HiveEntity = nullptr; // Hive entity reference + Vector Location = g_vecZero; // Origin of the hive + Vector FloorLocation = g_vecZero; // Some hives are suspended in the air, this is the floor location directly beneath it + HiveStatusType Status = HIVE_STATUS_UNBUILT; // Can be unbuilt, in progress, or fully built + AvHMessageID TechStatus = MESSAGE_NULL; // What tech (if any) is assigned to this hive right now + bool bIsUnderAttack = false; // Is the hive currently under attack? Becomes false if not taken damage for more than 10 seconds + AvHAIResourceNode* HiveResNodeRef = nullptr; // Which resource node (indexes into ResourceNodes array) belongs to this hive? + unsigned int ObstacleRefs[8]; // When in progress or built, will place an obstacle so bots don't try to walk through it + float NextFloorLocationCheck = 0.0f; // When should the closest navigable point to the hive be calculated? Used to delay the check after a hive is built + AvHTeamNumber OwningTeam = TEAM_IND; // Which team owns this hive currently (TEAM_IND if empty) + +} AvHAIHiveDefinition; + // 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 { @@ -446,6 +446,7 @@ typedef struct _NAV_STATUS bool bShouldWalk = false; // Should the bot walk at this point? + BotMoveStyle PreviousMoveStyle = MOVESTYLE_NORMAL; // Previous desired move style (e.g. normal, ambush, hide). Will trigger new path calculations if this changes 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 diff --git a/main/source/mod/AIPlayers/AvHAINavigation.cpp b/main/source/mod/AIPlayers/AvHAINavigation.cpp index 16d59886..ea851eae 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.cpp +++ b/main/source/mod/AIPlayers/AvHAINavigation.cpp @@ -4596,8 +4596,9 @@ void MarineUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) } } - if (MoveStyle == pBot->BotNavInfo.MoveStyle) { return; } + if (MoveStyle == pBot->BotNavInfo.PreviousMoveStyle) { return; } + pBot->BotNavInfo.PreviousMoveStyle = MoveStyle; pBot->BotNavInfo.bNavProfileChanged = true; pBot->BotNavInfo.MoveStyle = MoveStyle; @@ -4618,7 +4619,9 @@ void MarineUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) void SkulkUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) { - if (MoveStyle == pBot->BotNavInfo.MoveStyle) { return; } + if (MoveStyle == pBot->BotNavInfo.PreviousMoveStyle) { return; } + + pBot->BotNavInfo.PreviousMoveStyle = MoveStyle; pBot->BotNavInfo.bNavProfileChanged = true; pBot->BotNavInfo.MoveStyle = MoveStyle; @@ -4643,7 +4646,9 @@ void SkulkUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) void GorgeUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) { - if (MoveStyle == pBot->BotNavInfo.MoveStyle) { return; } + if (MoveStyle == pBot->BotNavInfo.PreviousMoveStyle) { return; } + + pBot->BotNavInfo.PreviousMoveStyle = MoveStyle; pBot->BotNavInfo.bNavProfileChanged = true; pBot->BotNavInfo.MoveStyle = MoveStyle; @@ -4667,7 +4672,9 @@ void GorgeUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) void LerkUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) { - if (MoveStyle == pBot->BotNavInfo.MoveStyle) { return; } + if (MoveStyle == pBot->BotNavInfo.PreviousMoveStyle) { return; } + + pBot->BotNavInfo.PreviousMoveStyle = MoveStyle; pBot->BotNavInfo.bNavProfileChanged = true; pBot->BotNavInfo.MoveStyle = MoveStyle; @@ -4693,7 +4700,9 @@ void LerkUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) void FadeUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle) { - if (MoveStyle == pBot->BotNavInfo.MoveStyle) { return; } + if (MoveStyle == pBot->BotNavInfo.PreviousMoveStyle) { return; } + + pBot->BotNavInfo.PreviousMoveStyle = MoveStyle; pBot->BotNavInfo.bNavProfileChanged = true; pBot->BotNavInfo.MoveStyle = MoveStyle; @@ -4773,7 +4782,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move } } - UpdateBotMoveProfile(pBot, MoveStyle); + pBot->BotNavInfo.MoveStyle = MoveStyle; UTIL_UpdateBotMovementStatus(pBot); bool bIsFlyingProfile = pBot->BotNavInfo.NavProfile.bFlyingProfile; @@ -4786,14 +4795,16 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move Vector MoveTaskDestination = g_vecZero; Vector MoveTaskOrigin = g_vecZero; + Vector MoveSecondaryOrigin = g_vecZero; if (bHasMovementTask) { MoveTaskDestination = BotNavInfo->MovementTask.TaskLocation; MoveTaskOrigin = (!FNullEnt(BotNavInfo->MovementTask.TaskTarget)) ? BotNavInfo->MovementTask.TaskTarget->v.origin : g_vecZero; + MoveSecondaryOrigin = (!FNullEnt(BotNavInfo->MovementTask.TaskSecondaryTarget)) ? BotNavInfo->MovementTask.TaskSecondaryTarget->v.origin : g_vecZero; } - bool bUltimateDestinationChanged = !vEquals(Destination, BotNavInfo->TargetDestination, GetPlayerRadius(pBot->Player)) && !vEquals(Destination, MoveTaskDestination) && !vEquals(Destination, MoveTaskOrigin); + bool bUltimateDestinationChanged = !vEquals(Destination, BotNavInfo->TargetDestination, GetPlayerRadius(pBot->Player)) && !vEquals(Destination, MoveTaskDestination) && !vEquals(Destination, MoveTaskOrigin) && !vEquals(Destination, MoveSecondaryOrigin); bool bHasReachedDestination = BotIsAtLocation(pBot, BotNavInfo->TargetDestination); @@ -4803,7 +4814,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move if (bIsFlyingProfile || AbortCurrentMove(pBot, Destination)) { // Don't clear the path if we're in the middle of a movement task - if (!vEquals(Destination, MoveTaskDestination) && !vEquals(Destination, MoveTaskOrigin)) + if (!vEquals(Destination, MoveTaskDestination) && !vEquals(Destination, MoveTaskOrigin) && !vEquals(Destination, MoveSecondaryOrigin)) { ClearBotPath(pBot); } @@ -4812,7 +4823,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move } else { - if (bHasMovementTask && !vEquals(Destination, MoveTaskDestination) && !vEquals(Destination, MoveTaskOrigin)) + if (bHasMovementTask && !vEquals(Destination, MoveTaskDestination) && !vEquals(Destination, MoveTaskOrigin) && !vEquals(Destination, MoveSecondaryOrigin)) { if (AITASK_IsTaskStillValid(pBot, &BotNavInfo->MovementTask)) { diff --git a/main/source/mod/AIPlayers/AvHAINavigation.h b/main/source/mod/AIPlayers/AvHAINavigation.h index 5f9aa130..12a83b95 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.h +++ b/main/source/mod/AIPlayers/AvHAINavigation.h @@ -12,6 +12,7 @@ #include "DetourStatus.h" #include "DetourNavMeshQuery.h" +#include "DetourTileCache.h" #include "AvHAIPlayer.h" /* Navigation profiles determine which nav mesh (regular, onos, building) is used for queries, and what @@ -31,7 +32,7 @@ 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. +constexpr auto 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 diff --git a/main/source/mod/AIPlayers/AvHAIPlayer.cpp b/main/source/mod/AIPlayers/AvHAIPlayer.cpp index 7be8131c..8fa287be 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayer.cpp +++ b/main/source/mod/AIPlayers/AvHAIPlayer.cpp @@ -1458,6 +1458,13 @@ void StartNewBotFrame(AvHAIPlayer* pBot) SetBaseNavProfile(pBot); } + UpdateBotMoveProfile(pBot, pBot->BotNavInfo.MoveStyle); + + if (IsPlayerMarine(pBot->Edict)) + { + UpdateCommanderOrders(pBot); + } + } void DroneThink(AvHAIPlayer* pBot) @@ -1466,7 +1473,12 @@ void DroneThink(AvHAIPlayer* pBot) pBot->CurrentTask = &pBot->PrimaryBotTask; - if (pBot->PrimaryBotTask.TaskType != TASK_NONE) + if (pBot->CommanderTask.TaskType != TASK_NONE) + { + BotProgressTask(pBot, &pBot->CommanderTask); + AITASK_ClearBotTask(pBot, &pBot->PrimaryBotTask); + } + else if (pBot->PrimaryBotTask.TaskType != TASK_NONE) { BotProgressTask(pBot, &pBot->PrimaryBotTask); } @@ -1489,11 +1501,10 @@ void TestNavThink(AvHAIPlayer* pBot) } BotProgressTask(pBot, &pBot->PrimaryBotTask); - //BotDrawPath(pBot, 0.0f, true); } else { - AvHAIResourceNode* RandomNode = AITAC_GetRandomResourceNode(); + AvHAIResourceNode* RandomNode = AITAC_GetRandomResourceNode(pBot->BotNavInfo.NavProfile.ReachabilityFlag); if (!RandomNode) { return; } @@ -1527,4 +1538,30 @@ void BotResumePlay(AvHAIPlayer* pBot) SetBaseNavProfile(pBot); pBot->bIsInactive = false; +} + +void UpdateCommanderOrders(AvHAIPlayer* pBot) +{ + OrderListType ActiveOrders = pBot->Player->GetActiveOrders(); + + for (auto it = ActiveOrders.begin(); it != ActiveOrders.end(); it++) + { + if (it->GetOrderActive() && it->GetReceiver() && ENTINDEX(pBot->Edict) == it->GetReceiver()) + { + Vector OrderLocation = g_vecZero; + it->GetLocation(OrderLocation); + + switch (it->GetOrderType()) + { + case ORDERTYPEL_MOVE: + AITASK_SetMoveTask(pBot, &pBot->CommanderTask, OrderLocation, true); + break; + case ORDERTYPET_BUILD: + AITASK_SetBuildTask(pBot, &pBot->CommanderTask, INDEXENT(it->GetTargetIndex()), true); + break; + default: + break; + } + } + } } \ No newline at end of file diff --git a/main/source/mod/AIPlayers/AvHAIPlayer.h b/main/source/mod/AIPlayers/AvHAIPlayer.h index f2f82301..142bbb32 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayer.h +++ b/main/source/mod/AIPlayers/AvHAIPlayer.h @@ -62,4 +62,6 @@ bool ShouldBotThink(AvHAIPlayer* pBot); void BotResumePlay(AvHAIPlayer* pBot); +void UpdateCommanderOrders(AvHAIPlayer* pBot); + #endif \ No newline at end of file diff --git a/main/source/mod/AIPlayers/AvHAITactical.cpp b/main/source/mod/AIPlayers/AvHAITactical.cpp index 4e957128..81de775b 100644 --- a/main/source/mod/AIPlayers/AvHAITactical.cpp +++ b/main/source/mod/AIPlayers/AvHAITactical.cpp @@ -25,11 +25,8 @@ #include -AvHAIResourceNode ResourceNodes[64]; -int NumTotalResNodes; - -AvHAIHiveDefinition Hives[3]; -int NumTotalHives; +vector ResourceNodes; +vector Hives; float CommanderViewZHeight; @@ -368,47 +365,52 @@ Vector AITAC_GetFloorLocationForHive(const AvHAIHiveDefinition* Hive) void AITAC_RefreshHiveData() { - if (NumTotalHives == 0) + if (Hives.size() == 0) { FOR_ALL_ENTITIES(kesTeamHive, AvHHive*) - Hives[NumTotalHives].HiveEntity = theEntity; - Hives[NumTotalHives].Location = theEntity->pev->origin; - Hives[NumTotalHives].HiveResNodeIndex = AITAC_FindNearestResNodeIndexToLocation(theEntity->pev->origin); - Hives[NumTotalHives].FloorLocation = UTIL_GetFloorUnderEntity(theEntity->edict()); // Some hives are suspended in the air, this is the floor location directly beneath it + AvHAIHiveDefinition NewHive; + NewHive.HiveEntity = theEntity; + NewHive.Location = theEntity->pev->origin; + NewHive.HiveResNodeRef = AITAC_GetNearestResourceNodeToLocation(theEntity->pev->origin); + NewHive.FloorLocation = UTIL_GetFloorUnderEntity(theEntity->edict()); // Some hives are suspended in the air, this is the floor location directly beneath it - NumTotalHives++; + Hives.push_back(NewHive); END_FOR_ALL_ENTITIES(kesTeamHive) } - for (int i = 0; i < NumTotalHives; i++) + int NextRefresh = 0; + + for (auto it = Hives.begin(); it != Hives.end(); it++) { - AvHHive* theEntity = Hives[i].HiveEntity; + AvHHive* theEntity = it->HiveEntity; - Hives[i].TechStatus = theEntity->GetTechnology(); - Hives[i].bIsUnderAttack = GetGameRules()->GetIsEntityUnderAttack(theEntity->entindex()); - Hives[i].OwningTeam = theEntity->GetTeamNumber(); - Hives[i].Status = (theEntity->GetIsActive() ? HIVE_STATUS_BUILT : (theEntity->GetIsSpawning() ? HIVE_STATUS_BUILDING : HIVE_STATUS_UNBUILT)); + it->TechStatus = theEntity->GetTechnology(); + it->bIsUnderAttack = GetGameRules()->GetIsEntityUnderAttack(theEntity->entindex()); + it->OwningTeam = theEntity->GetTeamNumber(); + it->Status = (theEntity->GetIsActive() ? HIVE_STATUS_BUILT : (theEntity->GetIsSpawning() ? HIVE_STATUS_BUILDING : HIVE_STATUS_UNBUILT)); - if (Hives[i].Status != HIVE_STATUS_UNBUILT && Hives[i].ObstacleRefs[REGULAR_NAV_MESH] == 0) + if (it->Status != HIVE_STATUS_UNBUILT && it->ObstacleRefs[REGULAR_NAV_MESH] == 0) { - UTIL_AddTemporaryObstacles(UTIL_GetCentreOfEntity(Hives[i].HiveEntity->edict()) - Vector(0.0f, 0.0f, 25.0f), 125.0f, 300.0f, DT_AREA_NULL, Hives[i].ObstacleRefs); - Hives[i].NextFloorLocationCheck = gpGlobals->time + 1.0f; + UTIL_AddTemporaryObstacles(UTIL_GetCentreOfEntity(it->HiveEntity->edict()) - Vector(0.0f, 0.0f, 25.0f), 125.0f, 300.0f, DT_AREA_NULL, it->ObstacleRefs); + it->NextFloorLocationCheck = gpGlobals->time + 1.0f; } - else if (Hives[i].Status == HIVE_STATUS_UNBUILT && Hives[i].ObstacleRefs[REGULAR_NAV_MESH] != 0) + else if (it->Status == HIVE_STATUS_UNBUILT && it->ObstacleRefs[REGULAR_NAV_MESH] != 0) { - UTIL_RemoveTemporaryObstacles(Hives[i].ObstacleRefs); - Hives[i].NextFloorLocationCheck = gpGlobals->time + 1.0f; + UTIL_RemoveTemporaryObstacles(it->ObstacleRefs); + it->NextFloorLocationCheck = gpGlobals->time + 1.0f; } - if (Hives[i].NextFloorLocationCheck > 0.0f && gpGlobals->time >= Hives[i].NextFloorLocationCheck) + if (it->NextFloorLocationCheck > 0.0f && gpGlobals->time >= it->NextFloorLocationCheck) { - Hives[i].FloorLocation = AITAC_GetFloorLocationForHive(&Hives[i]); + it->FloorLocation = AITAC_GetFloorLocationForHive(&(*it)); - Hives[i].NextFloorLocationCheck = gpGlobals->time + (5.0f + (0.1f * i)); + it->NextFloorLocationCheck = gpGlobals->time + (5.0f + (0.1f * NextRefresh)); } + + NextRefresh++; } } @@ -499,79 +501,95 @@ Vector AITAC_GetCommChairLocation(AvHTeamNumber Team) void AITAC_RefreshResourceNodes() { - if (NumTotalResNodes == 0) + if (ResourceNodes.size() == 0) { FOR_ALL_ENTITIES(kesFuncResource, AvHFuncResource*) - ResourceNodes[NumTotalResNodes].ResourceEntity = theEntity; - ResourceNodes[NumTotalResNodes].Location = theEntity->pev->origin; - ResourceNodes[NumTotalResNodes].ReachabilityFlags = AI_REACHABILITY_NONE; + AvHAIResourceNode NewResNode; + NewResNode.ResourceEntity = theEntity; + NewResNode.Location = theEntity->pev->origin; + NewResNode.ReachabilityFlags = AI_REACHABILITY_NONE; - 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); + bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), NewResNode.Location, max_player_use_reach); + bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), NewResNode.Location, max_player_use_reach); + bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), NewResNode.Location, max_player_use_reach); if (bIsReachableMarine) { - ResourceNodes[NumTotalResNodes].ReachabilityFlags |= AI_REACHABILITY_MARINE; + NewResNode.ReachabilityFlags |= AI_REACHABILITY_MARINE; + NewResNode.ReachabilityFlags |= AI_REACHABILITY_WELDER; + } + else + { + nav_profile WelderProfile; + memcpy(&WelderProfile, &BaseNavProfiles[MARINE_BASE_NAV_PROFILE], sizeof(nav_profile)); + + WelderProfile.Filters.removeExcludeFlags(SAMPLE_POLYFLAGS_WELD); + + bool bIsReachableWelder = UTIL_PointIsReachable(WelderProfile, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), NewResNode.Location, max_player_use_reach); + + if (bIsReachableWelder) + { + NewResNode.ReachabilityFlags |= AI_REACHABILITY_WELDER; + } } if (bIsReachableSkulk) { - ResourceNodes[NumTotalResNodes].ReachabilityFlags |= AI_REACHABILITY_SKULK; + NewResNode.ReachabilityFlags |= AI_REACHABILITY_SKULK; } if (bIsReachableOnos) { - ResourceNodes[NumTotalResNodes].ReachabilityFlags |= AI_REACHABILITY_ONOS; + NewResNode.ReachabilityFlags |= AI_REACHABILITY_ONOS; } - NumTotalResNodes++; + ResourceNodes.push_back(NewResNode); END_FOR_ALL_ENTITIES(kesFuncResource) } - for (int i = 0; i < NumTotalResNodes; i++) + for (auto it = ResourceNodes.begin(); it != ResourceNodes.end(); it++) { - AvHFuncResource* ResourceEntity = ResourceNodes[i].ResourceEntity; + AvHFuncResource* ResourceEntity = it->ResourceEntity; - ResourceNodes[i].bIsOccupied = ResourceEntity->GetIsOccupied(); + it->bIsOccupied = ResourceEntity->GetIsOccupied(); - if (ResourceNodes[i].bIsOccupied) + if (it->bIsOccupied) { DeployableSearchFilter TowerFilter; TowerFilter.DeployableTypes = (STRUCTURE_MARINE_RESTOWER | STRUCTURE_ALIEN_RESTOWER); - AvHAIBuildableStructure* OccupyingTower = AITAC_FindClosestDeployableToLocation(ResourceNodes[i].Location, &TowerFilter); + AvHAIBuildableStructure* OccupyingTower = AITAC_FindClosestDeployableToLocation(it->Location, &TowerFilter); if (OccupyingTower) { - ResourceNodes[i].ActiveTowerEntity = OccupyingTower->edict; - ResourceNodes[i].OwningTeam = OccupyingTower->EntityRef->GetTeamNumber(); + it->ActiveTowerEntity = OccupyingTower->edict; + it->OwningTeam = OccupyingTower->EntityRef->GetTeamNumber(); } } else { - ResourceNodes[i].ActiveTowerEntity = nullptr; - ResourceNodes[i].OwningTeam = TEAM_IND; + it->ActiveTowerEntity = nullptr; + it->OwningTeam = TEAM_IND; } } } -AvHAIResourceNode* AITAC_GetRandomResourceNode() +AvHAIResourceNode* AITAC_GetRandomResourceNode(const unsigned int ReachabilityFlags) { AvHAIResourceNode* Result = nullptr; float MaxScore = 0.0f; - for (int i = 0; i < NumTotalResNodes; i++) + for (auto it = ResourceNodes.begin(); it != ResourceNodes.end(); it++) { - if (!(ResourceNodes[i].ReachabilityFlags & AI_REACHABILITY_MARINE)) { continue; } + if (ReachabilityFlags != AI_REACHABILITY_NONE && !(it->ReachabilityFlags & ReachabilityFlags)) { continue; } float ThisScore = frandrange(0.0f, 1.0f); if (!Result || ThisScore > MaxScore) { - Result = &ResourceNodes[i]; + Result = &(*it); MaxScore = ThisScore; } } @@ -1054,6 +1072,8 @@ void AITAC_UpdateBuildableStructure(CBaseEntity* Structure) BuildingMap[EntIndex].StructureStatusFlags |= STRUCTURE_STATUS_UNDERATTACK; } + BuildingMap[EntIndex].LastSeen = StructureRefreshFrame; + } void AITAC_OnStructureCreated(AvHAIBuildableStructure* NewStructure) @@ -1102,8 +1122,7 @@ void AITAC_LinkDeployedItemToAction(AvHAIPlayer* CommanderBot, const AvHAIDroppe void AITAC_ClearMapAIData() { - memset(ResourceNodes, 0, sizeof(ResourceNodes)); - NumTotalResNodes = 0; + ResourceNodes.clear(); AITAC_ClearHiveInfo(); @@ -1123,38 +1142,19 @@ void AITAC_ClearMapAIData() void AITAC_ClearHiveInfo() { - memset(Hives, 0, sizeof(Hives)); - NumTotalHives = 0; -} - -int AITAC_FindNearestResNodeIndexToLocation(const Vector& Location) -{ - int Result = -1; - float MinDist = 0.0f; - - for (int i = 0; i < NumTotalResNodes; i++) + for (auto it = Hives.begin(); it != Hives.end(); it++) { - if (ResourceNodes[i].ResourceEntity) + if (it->ObstacleRefs[REGULAR_NAV_MESH] != 0) { - float ThisDist = vDist3DSq(Location, ResourceNodes[i].ResourceEntity->pev->origin); - - if (Result < 0 || ThisDist < MinDist) - { - Result = i; - MinDist = ThisDist; - } + UTIL_RemoveTemporaryObstacles(it->ObstacleRefs); } } - - return Result; + + Hives.clear(); } -bool AITAC_AlienHiveNeedsReinforcing(int HiveIndex) +bool AITAC_AlienHiveNeedsReinforcing(const AvHAIHiveDefinition* Hive) { - if (HiveIndex < 0 || HiveIndex >= NumTotalHives) { return false; } - - const AvHAIHiveDefinition* Hive = AITAC_GetHiveAtIndex(HiveIndex); - if (!Hive) { return false; } DeployableSearchFilter SearchFilter; @@ -1196,7 +1196,7 @@ bool AITAC_AlienHiveNeedsReinforcing(int HiveIndex) const AvHAIHiveDefinition* AITAC_GetHiveAtIndex(int Index) { - if (Index > -1 && Index < NumTotalHives) + if (Index > -1 && Index < Hives.size()) { return &Hives[Index]; } @@ -1457,11 +1457,11 @@ bool UTIL_StructureIsResearching(edict_t* Structure, const AvHMessageID Research AvHAIHiveDefinition* AITAC_GetHiveFromEdict(const edict_t* Edict) { - for (int i = 0; i < NumTotalHives; i++) + for (auto it = Hives.begin(); it != Hives.end(); it++) { - if (Hives[i].HiveEntity->edict() == Edict) + if (it->HiveEntity->edict() == Edict) { - return &Hives[i]; + return &(*it); } } @@ -1473,13 +1473,13 @@ const AvHAIHiveDefinition* AITAC_GetHiveNearestLocation(const Vector SearchLocat AvHAIHiveDefinition* Result = nullptr; float MinDist = 0.0f; - for (int i = 0; i < NumTotalHives; i++) + for (auto it = Hives.begin(); it != Hives.end(); it++) { - float ThisDist = vDist3DSq(SearchLocation, Hives[i].Location); + float ThisDist = vDist3DSq(SearchLocation, it->Location); if (!Result || ThisDist < MinDist) { - Result = &Hives[i]; + Result = &(*it); MinDist = ThisDist; } } @@ -1489,31 +1489,26 @@ const AvHAIHiveDefinition* AITAC_GetHiveNearestLocation(const Vector SearchLocat AvHAIResourceNode* AITAC_GetNearestResourceNodeToLocation(const Vector Location) { - int ResultIndex = -1; + AvHAIResourceNode* Result = nullptr; float CurrMinDist = 0; - for (int i = 0; i < NumTotalResNodes; i++) + for (auto it = ResourceNodes.begin(); it != ResourceNodes.end(); it++) { - float DistSq = vDist2DSq(ResourceNodes[i].Location, Location); + float DistSq = vDist2DSq(it->Location, Location); - if (ResultIndex < 0 || DistSq < CurrMinDist) + if (!Result || DistSq < CurrMinDist) { - ResultIndex = i; + Result = &(*it); CurrMinDist = DistSq; } } - if (ResultIndex > -1) - { - return &ResourceNodes[ResultIndex]; - } - - return nullptr; + return Result; } AvHAIResourceNode* AITAC_FindNearestResourceNodeToLocation(const Vector Location, const DeployableSearchFilter* Filter) { - int ResultIndex = -1; + AvHAIResourceNode* Result = nullptr; float MinDistSq = sqrf(Filter->MinSearchRadius); float MaxDistSq = sqrf(Filter->MaxSearchRadius); @@ -1523,25 +1518,20 @@ AvHAIResourceNode* AITAC_FindNearestResourceNodeToLocation(const Vector Location float CurrMinDist = 0; - for (int i = 0; i < NumTotalResNodes; i++) + for (auto it = ResourceNodes.begin(); it != ResourceNodes.end(); it++) { - if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(ResourceNodes[i].ReachabilityFlags & Filter->ReachabilityFlags)) { continue; } - if (ResourceNodes[i].OwningTeam != Filter->Team) { continue; } + if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(it->ReachabilityFlags & Filter->ReachabilityFlags)) { continue; } + if (it->OwningTeam != Filter->Team) { continue; } - float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(ResourceNodes[i].Location, Location)) : vDist2DSq(ResourceNodes[i].Location, Location); + float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it->Location, Location)) : vDist2DSq(it->Location, Location); - if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && (ResultIndex < 0 || DistSq < CurrMinDist)) + if ((!bUseMinDist || DistSq >= MinDistSq) && (!bUseMaxDist || DistSq <= MaxDistSq) && (!Result || DistSq < CurrMinDist)) { - ResultIndex = i; + Result = &(*it); } } - if (ResultIndex > -1) - { - return &ResourceNodes[ResultIndex]; - } - - return nullptr; + return Result; } @@ -1633,12 +1623,12 @@ AvHAIHiveDefinition* AITAC_GetTeamHiveWithTech(const AvHTeamNumber Team, const A if (!TeamRef || TeamRef->GetTeamType() != AVH_CLASS_TYPE_ALIEN) { return nullptr; } - for (int i = 0; i < NumTotalHives; i++) + for (auto it = Hives.begin(); it != Hives.end(); it++) { // Only return active hives with the tech - if (Hives[i].OwningTeam == Team && Hives[i].Status == HIVE_STATUS_BUILT && Hives[i].TechStatus == Tech) + if (it->OwningTeam == Team && it->Status == HIVE_STATUS_BUILT && it->TechStatus == Tech) { - return &Hives[i]; + return &(*it); } } @@ -1653,10 +1643,10 @@ bool AITAC_TeamHiveWithTechExists(const AvHTeamNumber Team, const AvHMessageID T if (!TeamRef || TeamRef->GetTeamType() != AVH_CLASS_TYPE_ALIEN) { return false; } - for (int i = 0; i < NumTotalHives; i++) + for (auto it = Hives.begin(); it != Hives.end(); it++) { // Only return active hives with the tech - if (Hives[i].OwningTeam == Team && Hives[i].Status == HIVE_STATUS_BUILT && Hives[i].TechStatus == Tech) + if (it->OwningTeam == Team && it->Status == HIVE_STATUS_BUILT && it->TechStatus == Tech) { return true; } @@ -1845,16 +1835,9 @@ int UTIL_GetCostOfStructureType(AvHAIDeployableStructureType StructureType) return 0; } -AvHAIResourceNode* AITAC_GetResourceNodeAtIndex(const int Index) -{ - if (Index < 0 || Index >= NumTotalResNodes) { return nullptr; } - - return &ResourceNodes[Index]; -} - int AITAC_GetNumHives() { - return NumTotalHives; + return Hives.size(); } AvHMessageID UTIL_StructureTypeToImpulseCommand(const AvHAIDeployableStructureType StructureType) diff --git a/main/source/mod/AIPlayers/AvHAITactical.h b/main/source/mod/AIPlayers/AvHAITactical.h index 209cf609..75c05b5e 100644 --- a/main/source/mod/AIPlayers/AvHAITactical.h +++ b/main/source/mod/AIPlayers/AvHAITactical.h @@ -36,19 +36,15 @@ void AITAC_LinkAlienStructureToTask(AvHAIPlayer* pBot, AvHAIBuildableStruct float AITAC_GetPhaseDistanceBetweenPoints(const Vector StartPoint, const Vector EndPoint); -int AITAC_FindNearestResNodeIndexToLocation(const Vector& Location); - const AvHAIHiveDefinition* AITAC_GetHiveAtIndex(int Index); const AvHAIHiveDefinition* AITAC_GetHiveNearestLocation(const Vector SearchLocation); Vector AITAC_GetCommChairLocation(AvHTeamNumber Team); edict_t* AITAC_GetCommChair(AvHTeamNumber Team); -AvHAIResourceNode* AITAC_GetResourceNodeAtIndex(const int Index); - Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team); -AvHAIResourceNode* AITAC_GetRandomResourceNode(); +AvHAIResourceNode* AITAC_GetRandomResourceNode(const unsigned int ReachabilityFlags); AvHAIDroppedItem* AITAC_FindClosestItemToLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance); @@ -70,7 +66,7 @@ void AITAC_ClearMapAIData(); // Clear out all the hive information void AITAC_ClearHiveInfo(); -bool AITAC_AlienHiveNeedsReinforcing(int HiveIndex); +bool AITAC_AlienHiveNeedsReinforcing(const AvHAIHiveDefinition* Hive); void AITAC_RefreshMarineItems(); void AITAC_UpdateMarineItem(CBaseEntity* Item, AvHAIDeployableItemType ItemType); diff --git a/main/source/mod/AIPlayers/AvHAITask.cpp b/main/source/mod/AIPlayers/AvHAITask.cpp index 85aa230f..5b2d436f 100644 --- a/main/source/mod/AIPlayers/AvHAITask.cpp +++ b/main/source/mod/AIPlayers/AvHAITask.cpp @@ -90,7 +90,7 @@ void AITASK_OnCompleteCommanderTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) AvHAIBuildableStructure* NearbyAlienTower = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &EnemyResTowerFilter); - if (!NearbyAlienTower) + if (NearbyAlienTower) { const AvHAIResourceNode* NodeRef = AITAC_GetNearestResourceNodeToLocation(NearbyAlienTower->Location); if (NodeRef) @@ -2196,13 +2196,22 @@ void BotProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) { MoveTo(pBot, Task->TaskSecondaryTarget->v.origin, MOVESTYLE_NORMAL); } + else + { + AvHAIDroppedItem* Welder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, 0.0f, 0.0f, true); + + if (Welder) + { + Task->TaskSecondaryTarget = Welder->edict; + } + } return; } if (IsPlayerInUseRange(pBot->Edict, Task->TaskTarget)) { - BotLookAt(pBot, UTIL_GetClosestPointOnEntityToLocation(pBot->CurrentEyePosition, Task->TaskTarget)); + BotLookAt(pBot, UTIL_GetClosestPointOnEntityToLocation(pBot->Edict->v.origin, Task->TaskTarget)); pBot->DesiredCombatWeapon = WEAPON_MARINE_WELDER; if (GetBotCurrentWeapon(pBot) != WEAPON_MARINE_WELDER) @@ -2280,7 +2289,7 @@ void MarineProgressSecureHiveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task) return; } - const AvHAIResourceNode* ResNode = AITAC_GetResourceNodeAtIndex(Hive->HiveResNodeIndex); + const AvHAIResourceNode* ResNode = Hive->HiveResNodeRef; if (ResNode && ResNode->OwningTeam != pBot->Player->GetTeam()) { @@ -2780,7 +2789,7 @@ void AITASK_SetAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Tar void AITASK_SetMoveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, const Vector Location, bool bIsUrgent) { - if (Task->TaskType == TASK_MOVE && vDist2DSq(Task->TaskLocation, Location) < sqrf(100.0f)) + if (Task->TaskType == TASK_MOVE && vDist2DSq(Task->TaskLocation, Location) < sqrf(16.0f)) { Task->bTaskIsUrgent = bIsUrgent; return; diff --git a/main/source/mod/AvHPlayer.h b/main/source/mod/AvHPlayer.h index 1cb61cc6..1d73f302 100644 --- a/main/source/mod/AvHPlayer.h +++ b/main/source/mod/AvHPlayer.h @@ -295,6 +295,7 @@ public: int GetExperienceLevel() const; AvHServerPlayerData* GetServerPlayerData(); + const OrderListType& GetActiveOrders() { return mClientOrders; } virtual bool GetHasItem(const char *szName); virtual void GiveNamedItem(const char *szName, bool inSendMessage = false); diff --git a/main/source/mod/AvHTeam.cpp b/main/source/mod/AvHTeam.cpp index d1914c5e..96d64c79 100644 --- a/main/source/mod/AvHTeam.cpp +++ b/main/source/mod/AvHTeam.cpp @@ -2331,7 +2331,7 @@ void AvHTeam::UpdateOrders() const float kExpireTime = 1.0f; if(!theOrderIter->GetOrderActive() && (theOrderIter->GetTimeOrderCompleted() != -1) && (gpGlobals->time > (theOrderIter->GetTimeOrderCompleted() + kExpireTime))) { - this->mOrderList.erase(theOrderIter); + theOrderIter = this->mOrderList.erase(theOrderIter); } else {