Added team-based reachability calculations

Reachabilities for structures and items are now based on the team, so bots understand when they can't reach a structure from their spawn point.
This commit is contained in:
RGreenlees 2023-10-19 17:49:01 +01:00 committed by pierow
parent d5e5a62968
commit 53b51d68a7
9 changed files with 410 additions and 121 deletions

View file

@ -85,8 +85,9 @@ 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_WELDER = 1u << 3,
AI_REACHABILITY_GORGE = 1u << 2,
AI_REACHABILITY_ONOS = 1u << 3,
AI_REACHABILITY_WELDER = 1u << 4,
AI_REACHABILITY_ALL = 0xFFFF
} AvHAIReachabilityStatus;
@ -170,14 +171,15 @@ typedef enum _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
bool bReachabilityMarkedDirty = false; // Reachability needs to be recalculated
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 TeamAReachabilityFlags = AI_REACHABILITY_NONE; // Is this reachable by the bots? Checks for marine reachability only
unsigned int TeamBReachabilityFlags = AI_REACHABILITY_NONE; // Is this reachable by the bots? Checks for marine reachability only
bool bReachabilityMarkedDirty = false; // Reachability needs to be recalculated
} AvHAIResourceNode;
// Data structure to hold information about each hive in the map
@ -214,7 +216,8 @@ typedef struct _DEPLOYABLE_SEARCH_FILTER
float MinSearchRadius = 0.0f;
float MaxSearchRadius = 0.0f;
bool bConsiderPhaseDistance = false;
AvHTeamNumber Team = TEAM_IND;
AvHTeamNumber DeployableTeam = TEAM_IND;
AvHTeamNumber ReachabilityTeam = TEAM_IND;
} DeployableSearchFilter;
// Pending message a bot wants to say. Allows for a delay in sending a message to simulate typing, or prevent too many messages on the same frame
@ -248,7 +251,8 @@ typedef struct _AVH_AI_BUILDABLE_STRUCTURE
float lastDamagedTime = 0.0f; // When it was last damaged by something. Used by bots to determine if still needs defending
AvHAIDeployableStructureType StructureType = STRUCTURE_NONE; // Type of structure it is (e.g. hive, comm chair, infantry portal, defence chamber etc.)
unsigned int StructureStatusFlags = STRUCTURE_STATUS_NONE;
unsigned int ReachabilityFlags = AI_REACHABILITY_NONE;
unsigned int TeamAReachabilityFlags = AI_REACHABILITY_NONE;
unsigned int TeamBReachabilityFlags = AI_REACHABILITY_NONE;
int LastSeen = 0; // Which refresh cycle was this last seen on? Used to determine if the building has been removed from play
unsigned int ObstacleRefs[8]; // References to this structure's obstacles across each nav mesh
Vector LastSuccessfulCommanderLocation = g_vecZero; // Tracks the last commander view location where it successfully placed or selected the building
@ -264,7 +268,8 @@ typedef struct _DROPPED_MARINE_ITEM
edict_t* edict = nullptr; // Reference to the item edict
Vector Location = g_vecZero; // Origin of the entity
AvHAIDeployableItemType ItemType = DEPLOYABLE_ITEM_NONE; // Is it a weapon, health pack, ammo pack etc?
unsigned int ReachabilityFlags = AI_REACHABILITY_NONE;
unsigned int TeamAReachabilityFlags = AI_REACHABILITY_NONE;
unsigned int TeamBReachabilityFlags = AI_REACHABILITY_NONE;
bool bReachabilityMarkedDirty = false; // Reachability needs to be recalculated
int LastSeen = 0; // Which refresh cycle was this last seen on? Used to determine if the item has been removed from play
} AvHAIDroppedItem;

View file

@ -4604,7 +4604,7 @@ void MarineUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle)
if (!bHasWelder)
{
AvHAIDroppedItem* NearbyWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, UTIL_MetresToGoldSrcUnits(10.0f), true);
AvHAIDroppedItem* NearbyWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->Player->GetTeam(), pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, UTIL_MetresToGoldSrcUnits(10.0f), true);
bHasWelder = (NearbyWelder != nullptr);
}
@ -5291,15 +5291,13 @@ void BotFollowPath(AvHAIPlayer* pBot)
{
AITASK_ClearBotTask(pBot, &pBot->BotNavInfo.MovementTask);
AvHAIDroppedItem* NearestWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, 0.0f, true);
AvHAIDroppedItem* NearestWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->Player->GetTeam(), pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, 0.0f, true);
if (NearestWelder)
{
AITASK_SetPickupTask(pBot, &pBot->BotNavInfo.MovementTask, NearestWelder->edict, true);
return;
}
}
}

View file

@ -84,6 +84,7 @@ typedef struct _DOOR_TRIGGER
edict_t* Edict = nullptr;
DoorActivationType TriggerType = DOOR_NONE;
bool bIsActivated = false;
CBaseEntity* TriggerChangeTargetRef = nullptr;
} DoorTrigger;
// Door reference. Not used, but is a future feature to allow bots to track if a door is open or not, and how to open it etc.

View file

@ -1504,7 +1504,7 @@ void TestNavThink(AvHAIPlayer* pBot)
}
else
{
AvHAIResourceNode* RandomNode = AITAC_GetRandomResourceNode(pBot->BotNavInfo.NavProfile.ReachabilityFlag);
AvHAIResourceNode* RandomNode = AITAC_GetRandomResourceNode((AvHTeamNumber)pBot->Edict->v.team, pBot->BotNavInfo.NavProfile.ReachabilityFlag);
if (!RandomNode) { return; }

View file

@ -63,14 +63,22 @@ bool AITAC_DeployableExistsAtLocation(const Vector& Location, const DeployableSe
bool bUseMinDist = MinDistSq > 0.1f;
bool bUseMaxDist = MaxDistSq > 0.1f;
if (Filter->Team == TeamA || Filter->Team == TEAM_IND)
if (Filter->DeployableTeam == TeamA || Filter->DeployableTeam == TEAM_IND)
{
for (auto& it : TeamAStructureMap)
{
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(it.second.ReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureType & Filter->DeployableTypes)
{
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
@ -83,14 +91,22 @@ bool AITAC_DeployableExistsAtLocation(const Vector& Location, const DeployableSe
}
}
if (Filter->Team == TeamB || Filter->Team == TEAM_IND)
if (Filter->DeployableTeam == TeamB || Filter->DeployableTeam == TEAM_IND)
{
for (auto& it : TeamBStructureMap)
{
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(it.second.ReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureType & Filter->DeployableTypes)
{
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
@ -120,14 +136,22 @@ AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocation(const Vector& Loc
bool bUseMinDist = MinDistSq > 0.1f;
bool bUseMaxDist = MaxDistSq > 0.1f;
if (Filter->Team == TeamA || Filter->Team == TEAM_IND)
if (Filter->DeployableTeam == TeamA || Filter->DeployableTeam == TEAM_IND)
{
for (auto& it : TeamAStructureMap)
{
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(it.second.ReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureType & Filter->DeployableTypes)
{
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
@ -141,14 +165,22 @@ AvHAIBuildableStructure* AITAC_FindClosestDeployableToLocation(const Vector& Loc
}
}
if (Filter->Team == TeamB || Filter->Team == TEAM_IND)
if (Filter->DeployableTeam == TeamB || Filter->DeployableTeam == TEAM_IND)
{
for (auto& it : TeamBStructureMap)
{
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(it.second.ReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureType & Filter->DeployableTypes)
{
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
@ -176,7 +208,7 @@ AvHAIDroppedItem* AITAC_GetDroppedItemRefFromEdict(edict_t* ItemEdict)
return &MarineDroppedItemMap[EntIndex];
}
AvHAIDroppedItem* AITAC_FindClosestItemToLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance)
AvHAIDroppedItem* AITAC_FindClosestItemToLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance)
{
AvHAIDroppedItem* Result = NULL;
float CurrMinDist = 0.0f;
@ -189,7 +221,15 @@ AvHAIDroppedItem* AITAC_FindClosestItemToLocation(const Vector& Location, const
for (auto& it : MarineDroppedItemMap)
{
if (ReachabilityFlags != AI_REACHABILITY_NONE && !(it.second.ReachabilityFlags & ReachabilityFlags)) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (SearchingTeam != TEAM_IND)
{
StructureReachabilityFlags = (SearchingTeam == GetGameRules()->GetTeamANumber()) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & ReachabilityFlags)) { continue; }
if (it.second.ItemType != ItemType) { continue; }
float DistSq = (bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
@ -234,14 +274,22 @@ AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer
bool bUseMinDist = MinDistSq > 0.1f;
bool bUseMaxDist = MaxDistSq > 0.1f;
if (Filter->Team == TeamA || Filter->Team == TEAM_IND)
if (Filter->DeployableTeam == TeamA || Filter->DeployableTeam == TEAM_IND)
{
for (auto& it : TeamAStructureMap)
{
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(it.second.ReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureType & Filter->DeployableTypes)
{
if (!UTIL_PointIsDirectlyReachable(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, it.second.Location)) { continue; }
@ -257,14 +305,22 @@ AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer
}
}
if (Filter->Team == TeamB || Filter->Team == TEAM_IND)
if (Filter->DeployableTeam == TeamB || Filter->DeployableTeam == TEAM_IND)
{
for (auto& it : TeamBStructureMap)
{
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(it.second.ReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureType & Filter->DeployableTypes)
{
if (!UTIL_PointIsDirectlyReachable(pBot->BotNavInfo.NavProfile, pBot->Edict->v.origin, it.second.Location)) { continue; }
@ -296,14 +352,22 @@ int AITAC_GetNumDeployablesNearLocation(const Vector& Location, const Deployable
int Result = 0;
if (Filter->Team == TeamA || Filter->Team == TEAM_IND)
if (Filter->DeployableTeam == TeamA || Filter->DeployableTeam == TEAM_IND)
{
for (auto& it : TeamAStructureMap)
{
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(it.second.ReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureType & Filter->DeployableTypes)
{
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
@ -316,14 +380,22 @@ int AITAC_GetNumDeployablesNearLocation(const Vector& Location, const Deployable
}
}
if (Filter->Team == TeamB || Filter->Team == TEAM_IND)
if (Filter->DeployableTeam == TeamB || Filter->DeployableTeam == TEAM_IND)
{
for (auto& it : TeamBStructureMap)
{
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(it.second.ReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureStatusFlags & Filter->ExcludeStatusFlags) { continue; }
if ((it.second.StructureStatusFlags & Filter->IncludeStatusFlags) != Filter->IncludeStatusFlags) { continue; }
unsigned int StructureReachabilityFlags = (it.second.TeamAReachabilityFlags | it.second.TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
StructureReachabilityFlags = (Filter->ReachabilityTeam == TeamA) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
}
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(StructureReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it.second.StructureType & Filter->DeployableTypes)
{
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it.second.Location, Location)) : vDist2DSq(it.second.Location, Location);
@ -441,6 +513,10 @@ Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team)
{
TeamAStartingLocation = AITAC_GetFloorLocationForHive(Hive);
}
else
{
TeamBStartingLocation = ZERO_VECTOR;
}
}
}
@ -460,10 +536,11 @@ Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team)
if (Hive)
{
if (Hive)
{
TeamBStartingLocation = AITAC_GetFloorLocationForHive(Hive);
}
TeamBStartingLocation = AITAC_GetFloorLocationForHive(Hive);
}
else
{
TeamBStartingLocation = ZERO_VECTOR;
}
}
}
@ -486,7 +563,8 @@ Vector AITAC_GetCommChairLocation(AvHTeamNumber Team)
DeployableSearchFilter ChairFilter;
ChairFilter.DeployableTypes = STRUCTURE_MARINE_COMMCHAIR;
ChairFilter.Team = Team;
ChairFilter.DeployableTeam = Team;
ChairFilter.ReachabilityTeam = TEAM_IND;
ChairFilter.bConsiderPhaseDistance = false;
ChairFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
@ -502,29 +580,33 @@ Vector AITAC_GetCommChairLocation(AvHTeamNumber Team)
void AITAC_RefreshReachabilityForItem(AvHAIDroppedItem* Item)
{
Item->ReachabilityFlags = AI_REACHABILITY_NONE;
if (Item->ItemType == DEPLOYABLE_ITEM_SCAN)
{
Item->ReachabilityFlags = AI_REACHABILITY_ALL;
Item->TeamAReachabilityFlags = AI_REACHABILITY_ALL;
Item->TeamBReachabilityFlags = AI_REACHABILITY_ALL;
return;
}
else
Item->TeamAReachabilityFlags = AI_REACHABILITY_NONE;
Item->TeamBReachabilityFlags = AI_REACHABILITY_NONE;
bool bOnNavMesh = UTIL_PointIsOnNavmesh(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], Item->edict->v.origin, Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach));
if (!bOnNavMesh)
{
bool bOnNavMesh = UTIL_PointIsOnNavmesh(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], Item->edict->v.origin, Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach));
if (!bOnNavMesh)
{
Item->ReachabilityFlags = AI_REACHABILITY_NONE;
return;
}
Item->TeamAReachabilityFlags = AI_REACHABILITY_NONE;
Item->TeamBReachabilityFlags = AI_REACHABILITY_NONE;
return;
}
if (GetGameRules()->GetTeamA()->GetTeamType() == AVH_CLASS_TYPE_MARINE)
{
bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), Item->edict->v.origin, max_player_use_reach);
if (bIsReachableMarine)
{
Item->ReachabilityFlags |= AI_REACHABILITY_MARINE;
Item->ReachabilityFlags |= AI_REACHABILITY_WELDER;
Item->TeamAReachabilityFlags |= AI_REACHABILITY_MARINE;
Item->TeamAReachabilityFlags |= AI_REACHABILITY_WELDER;
}
else
{
@ -537,7 +619,32 @@ void AITAC_RefreshReachabilityForItem(AvHAIDroppedItem* Item)
if (bIsReachableWelder)
{
Item->ReachabilityFlags |= AI_REACHABILITY_WELDER;
Item->TeamAReachabilityFlags |= AI_REACHABILITY_WELDER;
}
}
}
if (GetGameRules()->GetTeamB()->GetTeamType() == AVH_CLASS_TYPE_MARINE)
{
bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), Item->edict->v.origin, max_player_use_reach);
if (bIsReachableMarine)
{
Item->TeamBReachabilityFlags |= AI_REACHABILITY_MARINE;
Item->TeamBReachabilityFlags |= 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()->GetTeamBNumber()), Item->edict->v.origin, max_player_use_reach);
if (bIsReachableWelder)
{
Item->TeamBReachabilityFlags |= AI_REACHABILITY_WELDER;
}
}
}
@ -547,39 +654,110 @@ void AITAC_RefreshReachabilityForResNode(AvHAIResourceNode* ResNode)
{
ResNode->bReachabilityMarkedDirty = false;
bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNode->Location, max_player_use_reach);
ResNode->TeamAReachabilityFlags = AI_REACHABILITY_NONE;
ResNode->TeamBReachabilityFlags = AI_REACHABILITY_NONE;
if (bIsReachableMarine)
bool bOnNavMesh = UTIL_PointIsOnNavmesh(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], ResNode->Location, Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach));
if (!bOnNavMesh)
{
ResNode->ReachabilityFlags |= AI_REACHABILITY_MARINE;
ResNode->ReachabilityFlags |= AI_REACHABILITY_WELDER;
ResNode->TeamAReachabilityFlags = AI_REACHABILITY_NONE;
ResNode->TeamBReachabilityFlags = AI_REACHABILITY_NONE;
return;
}
if (GetGameRules()->GetTeamA()->GetTeamType() == AVH_CLASS_TYPE_MARINE)
{
bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNode->Location, max_player_use_reach);
if (bIsReachableMarine)
{
ResNode->TeamAReachabilityFlags |= AI_REACHABILITY_MARINE;
ResNode->TeamAReachabilityFlags |= 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()), ResNode->Location, max_player_use_reach);
if (bIsReachableWelder)
{
ResNode->TeamAReachabilityFlags |= AI_REACHABILITY_WELDER;
}
}
}
else
{
nav_profile WelderProfile;
memcpy(&WelderProfile, &BaseNavProfiles[MARINE_BASE_NAV_PROFILE], sizeof(nav_profile));
bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableGorge = UTIL_PointIsReachable(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNode->Location, max_player_use_reach);
WelderProfile.Filters.removeExcludeFlags(SAMPLE_POLYFLAGS_WELD);
bool bIsReachableWelder = UTIL_PointIsReachable(WelderProfile, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), ResNode->Location, max_player_use_reach);
if (bIsReachableWelder)
if (bIsReachableSkulk)
{
ResNode->ReachabilityFlags |= AI_REACHABILITY_WELDER;
ResNode->TeamAReachabilityFlags |= AI_REACHABILITY_SKULK;
}
if (bIsReachableGorge)
{
ResNode->TeamAReachabilityFlags |= AI_REACHABILITY_GORGE;
}
if (bIsReachableOnos)
{
ResNode->TeamAReachabilityFlags |= AI_REACHABILITY_ONOS;
}
}
if (bIsReachableSkulk)
if (GetGameRules()->GetTeamB()->GetTeamType() == AVH_CLASS_TYPE_MARINE)
{
ResNode->ReachabilityFlags |= AI_REACHABILITY_SKULK;
bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), ResNode->Location, max_player_use_reach);
if (bIsReachableMarine)
{
ResNode->TeamBReachabilityFlags |= AI_REACHABILITY_MARINE;
ResNode->TeamBReachabilityFlags |= 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()), ResNode->Location, max_player_use_reach);
if (bIsReachableWelder)
{
ResNode->TeamBReachabilityFlags |= AI_REACHABILITY_WELDER;
}
}
}
else
{
bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableGorge = UTIL_PointIsReachable(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), ResNode->Location, max_player_use_reach);
bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), ResNode->Location, max_player_use_reach);
if (bIsReachableSkulk)
{
ResNode->TeamBReachabilityFlags |= AI_REACHABILITY_SKULK;
}
if (bIsReachableGorge)
{
ResNode->TeamBReachabilityFlags |= AI_REACHABILITY_GORGE;
}
if (bIsReachableOnos)
{
ResNode->TeamBReachabilityFlags |= AI_REACHABILITY_ONOS;
}
}
if (bIsReachableOnos)
{
ResNode->ReachabilityFlags |= AI_REACHABILITY_ONOS;
}
}
void AITAC_RefreshResourceNodes()
@ -591,7 +769,8 @@ void AITAC_RefreshResourceNodes()
AvHAIResourceNode NewResNode;
NewResNode.ResourceEntity = theEntity;
NewResNode.Location = theEntity->pev->origin;
NewResNode.ReachabilityFlags = AI_REACHABILITY_NONE;
NewResNode.TeamAReachabilityFlags = AI_REACHABILITY_NONE;
NewResNode.TeamBReachabilityFlags = AI_REACHABILITY_NONE;
NewResNode.bReachabilityMarkedDirty = true;
ResourceNodes.push_back(NewResNode);
@ -631,14 +810,24 @@ void AITAC_RefreshResourceNodes()
}
}
AvHAIResourceNode* AITAC_GetRandomResourceNode(const unsigned int ReachabilityFlags)
AvHAIResourceNode* AITAC_GetRandomResourceNode(AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags)
{
AvHAIResourceNode* Result = nullptr;
float MaxScore = 0.0f;
for (auto it = ResourceNodes.begin(); it != ResourceNodes.end(); it++)
{
if (ReachabilityFlags != AI_REACHABILITY_NONE && !(it->ReachabilityFlags & ReachabilityFlags)) { continue; }
if (ReachabilityFlags != AI_REACHABILITY_NONE)
{
unsigned int StructureReachabilityFlags = (it->TeamAReachabilityFlags | it->TeamBReachabilityFlags);
if (SearchingTeam != TEAM_IND)
{
StructureReachabilityFlags = (SearchingTeam == GetGameRules()->GetTeamANumber()) ? it->TeamAReachabilityFlags : it->TeamBReachabilityFlags;
}
if (!(StructureReachabilityFlags & ReachabilityFlags)) { continue; }
}
float ThisScore = frandrange(0.0f, 1.0f);
@ -1030,43 +1219,103 @@ void AITAC_RefreshReachabilityForStructure(AvHAIBuildableStructure* Structure)
if (!bIsOnNavMesh)
{
Structure->ReachabilityFlags = AI_REACHABILITY_NONE;
Structure->TeamAReachabilityFlags = AI_REACHABILITY_NONE;
Structure->TeamBReachabilityFlags = AI_REACHABILITY_NONE;
return;
}
bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(Structure->edict), max_player_use_reach);
bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(Structure->edict), max_player_use_reach);
bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(Structure->edict), max_player_use_reach);
// Check if basic marines can reach. If they can then no need to separately check welder marines as they automatically can. If not, separately check for welders.
if (bIsReachableMarine)
if (GetGameRules()->GetTeamA()->GetTeamType() == AVH_CLASS_TYPE_MARINE)
{
Structure->ReachabilityFlags |= AI_REACHABILITY_MARINE;
Structure->ReachabilityFlags |= AI_REACHABILITY_WELDER;
bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(Structure->edict), max_player_use_reach);
// Check if basic marines can reach. If they can then no need to separately check welder marines as they automatically can. If not, separately check for welders.
if (bIsReachableMarine)
{
Structure->TeamAReachabilityFlags |= AI_REACHABILITY_MARINE;
Structure->TeamAReachabilityFlags |= 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()), UTIL_GetEntityGroundLocation(Structure->edict), max_player_use_reach);
if (bIsReachableWelder)
{
Structure->TeamAReachabilityFlags |= AI_REACHABILITY_WELDER;
}
}
}
else
{
nav_profile WelderProfile;
memcpy(&WelderProfile, &BaseNavProfiles[MARINE_BASE_NAV_PROFILE], sizeof(nav_profile));
bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(Structure->edict), max_player_use_reach);
bool bIsReachableGorge = UTIL_PointIsReachable(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(Structure->edict), max_player_use_reach);
bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(Structure->edict), max_player_use_reach);
WelderProfile.Filters.removeExcludeFlags(SAMPLE_POLYFLAGS_WELD);
bool bIsReachableWelder = UTIL_PointIsReachable(WelderProfile, AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber()), UTIL_GetEntityGroundLocation(Structure->edict), max_player_use_reach);
if (bIsReachableWelder)
if (bIsReachableSkulk)
{
Structure->ReachabilityFlags |= AI_REACHABILITY_WELDER;
Structure->TeamAReachabilityFlags |= AI_REACHABILITY_SKULK;
}
if (bIsReachableGorge)
{
Structure->TeamAReachabilityFlags |= AI_REACHABILITY_GORGE;
}
if (bIsReachableOnos)
{
Structure->TeamAReachabilityFlags |= AI_REACHABILITY_ONOS;
}
}
if (bIsReachableSkulk)
if (GetGameRules()->GetTeamB()->GetTeamType() == AVH_CLASS_TYPE_MARINE)
{
Structure->ReachabilityFlags |= AI_REACHABILITY_SKULK;
}
bool bIsReachableMarine = UTIL_PointIsReachable(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), UTIL_GetEntityGroundLocation(Structure->edict), max_player_use_reach);
if (bIsReachableOnos)
// Check if basic marines can reach. If they can then no need to separately check welder marines as they automatically can. If not, separately check for welders.
if (bIsReachableMarine)
{
Structure->TeamBReachabilityFlags |= AI_REACHABILITY_MARINE;
Structure->TeamBReachabilityFlags |= 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()), UTIL_GetEntityGroundLocation(Structure->edict), max_player_use_reach);
if (bIsReachableWelder)
{
Structure->TeamBReachabilityFlags |= AI_REACHABILITY_WELDER;
}
}
}
else
{
Structure->ReachabilityFlags |= AI_REACHABILITY_ONOS;
bool bIsReachableSkulk = UTIL_PointIsReachable(BaseNavProfiles[SKULK_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), UTIL_GetEntityGroundLocation(Structure->edict), max_player_use_reach);
bool bIsReachableGorge = UTIL_PointIsReachable(BaseNavProfiles[GORGE_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), UTIL_GetEntityGroundLocation(Structure->edict), max_player_use_reach);
bool bIsReachableOnos = UTIL_PointIsReachable(BaseNavProfiles[ONOS_BASE_NAV_PROFILE], AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber()), UTIL_GetEntityGroundLocation(Structure->edict), max_player_use_reach);
if (bIsReachableSkulk)
{
Structure->TeamBReachabilityFlags |= AI_REACHABILITY_SKULK;
}
if (bIsReachableGorge)
{
Structure->TeamBReachabilityFlags |= AI_REACHABILITY_GORGE;
}
if (bIsReachableOnos)
{
Structure->TeamBReachabilityFlags |= AI_REACHABILITY_ONOS;
}
}
}
@ -1248,7 +1497,8 @@ bool AITAC_AlienHiveNeedsReinforcing(const AvHAIHiveDefinition* Hive)
SearchFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
SearchFilter.IncludeStatusFlags = 0;
SearchFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
SearchFilter.Team = Hive->OwningTeam;
SearchFilter.DeployableTeam = Hive->OwningTeam;
SearchFilter.ReachabilityTeam = TEAM_IND;
int NumOffenceChambers = AITAC_GetNumDeployablesNearLocation(Hive->FloorLocation, &SearchFilter);
@ -1467,7 +1717,9 @@ bool UTIL_IsBuildableStructureStillReachable(AvHAIPlayer* pBot, const edict_t* S
if (!StructureRef) { return false; }
return (StructureRef->ReachabilityFlags & pBot->BotNavInfo.NavProfile.ReachabilityFlag) != 0;
unsigned int TeamReachability = (pBot->Edict->v.team == GetGameRules()->GetTeamANumber()) ? StructureRef->TeamAReachabilityFlags : StructureRef->TeamBReachabilityFlags;
return (TeamReachability & pBot->BotNavInfo.NavProfile.ReachabilityFlag);
}
bool UTIL_IsDroppedItemStillReachable(AvHAIPlayer* pBot, const edict_t* Item)
@ -1476,7 +1728,9 @@ bool UTIL_IsDroppedItemStillReachable(AvHAIPlayer* pBot, const edict_t* Item)
if (Index < 0) { return false; }
return (MarineDroppedItemMap[Index].ReachabilityFlags & pBot->BotNavInfo.NavProfile.ReachabilityFlag);
unsigned int TeamReachability = (pBot->Edict->v.team == GetGameRules()->GetTeamANumber()) ? MarineDroppedItemMap[Index].TeamAReachabilityFlags : MarineDroppedItemMap[Index].TeamBReachabilityFlags;
return (TeamReachability & pBot->BotNavInfo.NavProfile.ReachabilityFlag);
}
AvHAIWeapon UTIL_GetWeaponTypeFromEdict(const edict_t* ItemEdict)
@ -1607,8 +1861,20 @@ AvHAIResourceNode* AITAC_FindNearestResourceNodeToLocation(const Vector Location
for (auto it = ResourceNodes.begin(); it != ResourceNodes.end(); it++)
{
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE && !(it->ReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
if (it->OwningTeam != Filter->Team) { continue; }
if (Filter->ReachabilityFlags != AI_REACHABILITY_NONE)
{
unsigned int CheckReachabilityFlags = (it->TeamAReachabilityFlags | it->TeamBReachabilityFlags);
if (Filter->ReachabilityTeam != TEAM_IND)
{
CheckReachabilityFlags = (Filter->ReachabilityTeam == GetGameRules()->GetTeamANumber()) ? it->TeamAReachabilityFlags : it->TeamBReachabilityFlags;
}
if (!(CheckReachabilityFlags & Filter->ReachabilityFlags)) { continue; }
}
if (it->OwningTeam != Filter->DeployableTeam) { continue; }
float DistSq = (Filter->bConsiderPhaseDistance) ? sqrf(AITAC_GetPhaseDistanceBetweenPoints(it->Location, Location)) : vDist2DSq(it->Location, Location);
@ -1791,7 +2057,9 @@ Vector UTIL_GetNextMinePosition(edict_t* StructureToMine)
for (auto& it : BuildingMap)
{
if (it.second.StructureType != STRUCTURE_MARINE_DEPLOYEDMINE || !(it.second.ReachabilityFlags & AI_REACHABILITY_MARINE)) { continue; }
unsigned int TeamReachabilityFlag = (StructureTeam == TeamANumber) ? it.second.TeamAReachabilityFlags : it.second.TeamBReachabilityFlags;
if (it.second.StructureType != STRUCTURE_MARINE_DEPLOYEDMINE || !(TeamReachabilityFlag & AI_REACHABILITY_MARINE)) { continue; }
if (vDist2DSq(StructureToMine->v.origin, it.second.Location) > sqrf(UTIL_MetresToGoldSrcUnits(2.0f))) { continue; }
@ -2077,7 +2345,8 @@ edict_t* AITAC_GetCommChair(AvHTeamNumber Team)
DeployableSearchFilter ChairFilter;
ChairFilter.DeployableTypes = STRUCTURE_MARINE_COMMCHAIR;
ChairFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
ChairFilter.Team = Team;
ChairFilter.DeployableTeam = Team;
ChairFilter.ReachabilityTeam = TEAM_IND;
AvHAIBuildableStructure* ChairStructure = AITAC_FindClosestDeployableToLocation(ZERO_VECTOR, &ChairFilter);
@ -2086,7 +2355,7 @@ edict_t* AITAC_GetCommChair(AvHTeamNumber Team)
return ChairStructure->edict;
}
ChairFilter.Team = TEAM_IND;
ChairFilter.DeployableTeam = TEAM_IND;
ChairStructure = AITAC_FindClosestDeployableToLocation(AITAC_GetTeamStartingLocation(Team), &ChairFilter);

View file

@ -47,9 +47,9 @@ edict_t* AITAC_GetCommChair(AvHTeamNumber Team);
Vector AITAC_GetTeamStartingLocation(AvHTeamNumber Team);
AvHAIResourceNode* AITAC_GetRandomResourceNode(const unsigned int ReachabilityFlags);
AvHAIResourceNode* AITAC_GetRandomResourceNode(AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags);
AvHAIDroppedItem* AITAC_FindClosestItemToLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance);
AvHAIDroppedItem* AITAC_FindClosestItemToLocation(const Vector& Location, const AvHAIDeployableItemType ItemType, AvHTeamNumber SearchingTeam, const unsigned int ReachabilityFlags, float MinRadius, float MaxRadius, bool bConsiderPhaseDistance);
AvHAIDroppedItem* AITAC_GetDroppedItemRefFromEdict(edict_t* ItemEdict);

View file

@ -84,8 +84,9 @@ void AITASK_OnCompleteCommanderTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
DeployableSearchFilter EnemyResTowerFilter;
EnemyResTowerFilter.DeployableTypes = SEARCH_ANY_RES_TOWER;
EnemyResTowerFilter.Team = (AIMGR_GetEnemyTeam(pBot->Player->GetTeam()));
EnemyResTowerFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
EnemyResTowerFilter.DeployableTeam = (AIMGR_GetEnemyTeam(pBot->Player->GetTeam()));
EnemyResTowerFilter.ReachabilityFlags = pBot->BotNavInfo.NavProfile.ReachabilityFlag;
EnemyResTowerFilter.ReachabilityTeam = (AvHTeamNumber)pBot->Edict->v.team;
EnemyResTowerFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
AvHAIBuildableStructure* NearbyAlienTower = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &EnemyResTowerFilter);
@ -373,7 +374,7 @@ bool AITASK_IsWeldTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
if (FNullEnt(Task->TaskSecondaryTarget))
{
AvHAIDroppedItem* NearestWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, 0.0f, true);
AvHAIDroppedItem* NearestWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->Player->GetTeam(), pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, 0.0f, true);
if (NearestWelder)
{
@ -523,7 +524,7 @@ bool AITASK_IsMineStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Ta
MineFilter.DeployableTypes = STRUCTURE_MARINE_DEPLOYEDMINE;
MineFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(2.0f);
MineFilter.bConsiderPhaseDistance = false;
MineFilter.Team = pBot->Player->GetTeam();
MineFilter.DeployableTeam = pBot->Player->GetTeam();
if (AITAC_GetNumDeployablesNearLocation(Task->TaskTarget->v.origin, &MineFilter) >= 4) { return false; }
@ -668,7 +669,7 @@ bool AITASK_IsAlienBuildTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
DeployableSearchFilter StructureFilter;
StructureFilter.DeployableTypes = Task->StructureType;
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
StructureFilter.Team = pBot->Player->GetTeam();
StructureFilter.DeployableTeam = pBot->Player->GetTeam();
// Don't build more if we've already got quite a few in the immediate vicinity. Helps prevent structure spam
if (AITAC_GetNumDeployablesNearLocation(Task->TaskLocation, &StructureFilter) >= 3)
@ -817,7 +818,7 @@ bool AITASK_IsReinforceStructureTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTas
DeployableSearchFilter StructureFilter;
StructureFilter.DeployableTypes = STRUCTURE_ALIEN_OFFENCECHAMBER;
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
StructureFilter.Team = pBot->Player->GetTeam();
StructureFilter.DeployableTeam = pBot->Player->GetTeam();
// At least 2 offence chambers
int NumOffenceChambers = AITAC_GetNumDeployablesNearLocation(Task->TaskTarget->v.origin, &StructureFilter);
@ -1176,7 +1177,7 @@ void BotProgressReinforceStructureTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
DeployableSearchFilter StructureFilter;
StructureFilter.DeployableTypes = ChamberTypeOne;
StructureFilter.Team = pBot->Player->GetTeam();
StructureFilter.DeployableTeam = pBot->Player->GetTeam();
int NumHiveTechOne = AITAC_GetNumDeployablesNearLocation(ZERO_VECTOR, &StructureFilter);
StructureFilter.DeployableTypes = ChamberTypeTwo;
@ -2198,7 +2199,7 @@ void BotProgressWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
else
{
AvHAIDroppedItem* Welder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, 0.0f, true);
AvHAIDroppedItem* Welder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->Player->GetTeam(), pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, 0.0f, true);
if (Welder)
{
@ -2707,7 +2708,7 @@ void AITASK_SetWeldTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task, edict_t* Targe
if (!PlayerHasWeapon(pBot->Player, WEAPON_MARINE_WELDER))
{
AvHAIDroppedItem* NearestWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, 0.0f, true);
AvHAIDroppedItem* NearestWelder = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_WELDER, pBot->Player->GetTeam(), pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, 0.0f, true);
if (!NearestWelder)
{

View file

@ -638,7 +638,9 @@ AvHAIWeapon BotAlienChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* tar
DeployableSearchFilter SearchFilter;
SearchFilter.DeployableTypes = StructureSearchType;
SearchFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
SearchFilter.Team = EnemyTeam;
SearchFilter.DeployableTeam = EnemyTeam;
SearchFilter.ReachabilityTeam = TEAM_IND;
SearchFilter.ReachabilityFlags = AI_REACHABILITY_NONE;
NumEnemyTargetsInArea += AITAC_GetNumDeployablesNearLocation(target->v.origin, &SearchFilter);
}
@ -736,7 +738,7 @@ AvHAIWeapon SkulkGetBestWeaponForCombatTarget(AvHAIPlayer* pBot, edict_t* Target
DeployableSearchFilter SearchFilter;
SearchFilter.DeployableTypes = StructureSearchType;
SearchFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
SearchFilter.Team = EnemyTeam;
SearchFilter.DeployableTeam = EnemyTeam;
NumEnemyTargetsInArea += AITAC_GetNumDeployablesNearLocation(Target->v.origin, &SearchFilter);
}

View file

@ -112,6 +112,7 @@
#include "AIPlayers/AvHAINavigation.h"
#include "AIPlayers/AvHAIPlayerManager.h"
#include "AIPlayers/AvHAITask.h"
#include "AIPlayers/AvHAITactical.h"
extern AvHParticleTemplateListServer gParticleTemplateList;
extern CVoiceGameMgr g_VoiceGameMgr;
@ -1451,6 +1452,18 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
}
}
theSuccess = true;
}
else if (FStrEq(pcmd, "aiteamstarts"))
{
Vector TeamOneLoc = AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber());
UTIL_DrawLine(INDEXENT(1), INDEXENT(1)->v.origin, TeamOneLoc, 10.0f, 0, 0, 255);
Vector TeamTwoLoc = AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber());
UTIL_DrawLine(INDEXENT(1), INDEXENT(1)->v.origin, TeamTwoLoc, 10.0f, 0, 128, 0);
theSuccess = true;
}
else if( FStrEq( pcmd, kcRemoveUpgrade) )