Replaced fixed arrays with vectors

* Resource node and hive lists are now vectors.
* Further improved bot weld behaviour
This commit is contained in:
RGreenlees 2023-10-17 23:08:07 +01:00 committed by pierow
parent d15e7bfdad
commit 410351149e
10 changed files with 214 additions and 173 deletions

View file

@ -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

View file

@ -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))
{

View file

@ -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

View file

@ -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;
}
}
}
}

View file

@ -62,4 +62,6 @@ bool ShouldBotThink(AvHAIPlayer* pBot);
void BotResumePlay(AvHAIPlayer* pBot);
void UpdateCommanderOrders(AvHAIPlayer* pBot);
#endif

View file

@ -25,11 +25,8 @@
#include <unordered_map>
AvHAIResourceNode ResourceNodes[64];
int NumTotalResNodes;
AvHAIHiveDefinition Hives[3];
int NumTotalHives;
vector<AvHAIResourceNode> ResourceNodes;
vector<AvHAIHiveDefinition> 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)

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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
{