diff --git a/main/source/mod/AIPlayers/AvHAIConstants.h b/main/source/mod/AIPlayers/AvHAIConstants.h index d5fd0d92..49881d0e 100644 --- a/main/source/mod/AIPlayers/AvHAIConstants.h +++ b/main/source/mod/AIPlayers/AvHAIConstants.h @@ -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; diff --git a/main/source/mod/AIPlayers/AvHAINavigation.cpp b/main/source/mod/AIPlayers/AvHAINavigation.cpp index e6523459..6d87e34d 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.cpp +++ b/main/source/mod/AIPlayers/AvHAINavigation.cpp @@ -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; } - - } } diff --git a/main/source/mod/AIPlayers/AvHAINavigation.h b/main/source/mod/AIPlayers/AvHAINavigation.h index 12a83b95..ec668975 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.h +++ b/main/source/mod/AIPlayers/AvHAINavigation.h @@ -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. diff --git a/main/source/mod/AIPlayers/AvHAIPlayer.cpp b/main/source/mod/AIPlayers/AvHAIPlayer.cpp index 8fa287be..9253cd74 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayer.cpp +++ b/main/source/mod/AIPlayers/AvHAIPlayer.cpp @@ -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; } diff --git a/main/source/mod/AIPlayers/AvHAITactical.cpp b/main/source/mod/AIPlayers/AvHAITactical.cpp index e1dab1b2..86194409 100644 --- a/main/source/mod/AIPlayers/AvHAITactical.cpp +++ b/main/source/mod/AIPlayers/AvHAITactical.cpp @@ -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); diff --git a/main/source/mod/AIPlayers/AvHAITactical.h b/main/source/mod/AIPlayers/AvHAITactical.h index 0ba5ee8e..db3c6236 100644 --- a/main/source/mod/AIPlayers/AvHAITactical.h +++ b/main/source/mod/AIPlayers/AvHAITactical.h @@ -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); diff --git a/main/source/mod/AIPlayers/AvHAITask.cpp b/main/source/mod/AIPlayers/AvHAITask.cpp index 1e8d3bb0..48b0f367 100644 --- a/main/source/mod/AIPlayers/AvHAITask.cpp +++ b/main/source/mod/AIPlayers/AvHAITask.cpp @@ -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) { diff --git a/main/source/mod/AIPlayers/AvHAIWeaponHelper.cpp b/main/source/mod/AIPlayers/AvHAIWeaponHelper.cpp index efd48ee3..ab354e7d 100644 --- a/main/source/mod/AIPlayers/AvHAIWeaponHelper.cpp +++ b/main/source/mod/AIPlayers/AvHAIWeaponHelper.cpp @@ -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); } diff --git a/main/source/mod/AvHConsoleCommands.cpp b/main/source/mod/AvHConsoleCommands.cpp index 83685fd9..efc5d7c4 100644 --- a/main/source/mod/AvHConsoleCommands.cpp +++ b/main/source/mod/AvHConsoleCommands.cpp @@ -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) )