mirror of
https://github.com/ENSL/NS.git
synced 2025-04-20 16:30:56 +00:00
Commander improvements
This commit is contained in:
parent
b78629738d
commit
aa314842ce
9 changed files with 368 additions and 94 deletions
|
@ -16,14 +16,27 @@ bool AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureTyp
|
|||
AvHMessageID StructureID = UTIL_StructureTypeToImpulseCommand(StructureToDeploy);
|
||||
|
||||
Vector BuildLocation = Location;
|
||||
BuildLocation.z += 4.0f;
|
||||
|
||||
UTIL_DrawLine(INDEXENT(1), INDEXENT(1)->v.origin, Location, 10.0f);
|
||||
|
||||
if (!AvHSHUGetIsSiteValidForBuild(StructureID, &BuildLocation)) { return false; }
|
||||
|
||||
CBaseEntity* NewBuilding = AvHSUBuildTechForPlayer(StructureID, BuildLocation, pBot->Player);
|
||||
string theErrorMessage;
|
||||
int theCost = 0;
|
||||
bool thePurchaseAllowed = pBot->Player->GetPurchaseAllowed(StructureID, theCost, &theErrorMessage);
|
||||
|
||||
if (!thePurchaseAllowed) { return false; }
|
||||
|
||||
bool theSuccess = (AvHSUBuildTechForPlayer(StructureID, BuildLocation, pBot->Player) != NULL);
|
||||
|
||||
if (!theSuccess) { return false; }
|
||||
|
||||
pBot->Player->PayPurchaseCost(theCost);
|
||||
|
||||
pBot->next_commander_action_time = gpGlobals->time + 1.0f;
|
||||
|
||||
return NewBuilding != nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AICOMM_DeployItem(AvHAIPlayer* pBot, const AvHAIDeployableItemType ItemToDeploy, const Vector Location)
|
||||
|
@ -32,25 +45,38 @@ bool AICOMM_DeployItem(AvHAIPlayer* pBot, const AvHAIDeployableItemType ItemToDe
|
|||
|
||||
Vector BuildLocation = Location;
|
||||
|
||||
string theErrorMessage;
|
||||
int theCost = 0;
|
||||
bool thePurchaseAllowed = pBot->Player->GetPurchaseAllowed(StructureID, theCost, &theErrorMessage);
|
||||
|
||||
if (!thePurchaseAllowed) { return false; }
|
||||
|
||||
if (!AvHSHUGetIsSiteValidForBuild(StructureID, &BuildLocation)) { return false; }
|
||||
|
||||
CBaseEntity* NewBuilding = AvHSUBuildTechForPlayer(StructureID, BuildLocation, pBot->Player);
|
||||
bool theSuccess = (AvHSUBuildTechForPlayer(StructureID, BuildLocation, pBot->Player) != NULL);
|
||||
|
||||
if (!theSuccess) { return false; }
|
||||
|
||||
pBot->Player->PayPurchaseCost(theCost);
|
||||
|
||||
pBot->next_commander_action_time = gpGlobals->time + 0.2f;
|
||||
|
||||
return NewBuilding != nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AICOMM_ResearchTech(AvHAIPlayer* pBot, AvHAIBuildableStructure* StructureToResearch, AvHMessageID Research)
|
||||
{
|
||||
if (FNullEnt(StructureToResearch->edict)) { return false; }
|
||||
|
||||
if (StructureToResearch->EntityRef->GetIsRecycling() || StructureToResearch->EntityRef->GetIsResearching()) { return false; }
|
||||
// Don't do anything if the structure is being recycled, or we DON'T want to recycle but the structure is already busy
|
||||
if (StructureToResearch->EntityRef->GetIsRecycling() || (Research != BUILD_RECYCLE && StructureToResearch->EntityRef->GetIsResearching())) { return false; }
|
||||
|
||||
int StructureIndex = ENTINDEX(StructureToResearch->edict);
|
||||
|
||||
if (StructureIndex < 0) { return false; }
|
||||
|
||||
if (!StructureToResearch->EntityRef->GetIsTechnologyAvailable(Research)) { return false; }
|
||||
|
||||
pBot->Player->SetSelection(StructureIndex, true);
|
||||
|
||||
pBot->Button |= IN_ATTACK2;
|
||||
|
@ -72,6 +98,7 @@ bool AICOMM_UpgradeStructure(AvHAIPlayer* pBot, AvHAIBuildableStructure* Structu
|
|||
break;
|
||||
case STRUCTURE_MARINE_TURRETFACTORY:
|
||||
UpgradeImpulse = TURRET_FACTORY_UPGRADE;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -376,7 +403,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot, commander_action* Action)
|
|||
StructureFilter.DeployableTeam = TeamNumber;
|
||||
StructureFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
|
||||
StructureFilter.ReachabilityTeam = TeamNumber;
|
||||
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
|
||||
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
||||
|
||||
int NumInfantryPortals = AITAC_GetNumDeployablesNearLocation(CommChair->v.origin, &StructureFilter);
|
||||
|
||||
|
@ -389,7 +416,6 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot, commander_action* Action)
|
|||
}
|
||||
|
||||
StructureFilter.DeployableTypes = STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY;
|
||||
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
||||
|
||||
AvHAIBuildableStructure* BaseArmoury = AITAC_FindClosestDeployableToLocation(CommChair->v.origin, &StructureFilter);
|
||||
|
||||
|
@ -405,12 +431,12 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot, commander_action* Action)
|
|||
|
||||
if (NearestInfantryPortal)
|
||||
{
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), NearestInfantryPortal->Location, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestInfantryPortal->Location, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
}
|
||||
|
||||
if (vIsZero(BuildLocation))
|
||||
{
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
|
||||
}
|
||||
|
||||
if (!vIsZero(BuildLocation))
|
||||
|
@ -430,7 +456,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot, commander_action* Action)
|
|||
|
||||
if (!bAlreadyScanning)
|
||||
{
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(ALL_NAV_PROFILE), HiveUnderSiege->FloorLocation, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), HiveUnderSiege->FloorLocation, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
|
||||
if (AICOMM_DeployItem(pBot, DEPLOYABLE_ITEM_SCAN, BuildLocation))
|
||||
{
|
||||
|
@ -448,7 +474,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot, commander_action* Action)
|
|||
|
||||
if (!bPhaseNearBase)
|
||||
{
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
|
||||
|
||||
if (AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation))
|
||||
{
|
||||
|
@ -484,7 +510,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot, commander_action* Action)
|
|||
|
||||
if (!bHasArmsLab)
|
||||
{
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
|
||||
|
||||
if (!vIsZero(BuildLocation))
|
||||
{
|
||||
|
@ -501,7 +527,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot, commander_action* Action)
|
|||
|
||||
if (!bHasObservatory)
|
||||
{
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(10.0f));
|
||||
|
||||
if (!vIsZero(BuildLocation))
|
||||
{
|
||||
|
@ -564,7 +590,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot, commander_action* Action)
|
|||
|
||||
if (!bHasPrototypeLab && bHasAdvArmoury)
|
||||
{
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInDonut(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), BaseArmoury->Location, UTIL_MetresToGoldSrcUnits(3.0f), UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInDonutIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), BaseArmoury->Location, UTIL_MetresToGoldSrcUnits(3.0f), UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
if (!vIsZero(BuildLocation))
|
||||
{
|
||||
|
@ -775,35 +801,39 @@ const AvHAIHiveDefinition* AICOMM_GetHiveSiegeOpportunityNearestLocation(AvHAIPl
|
|||
|
||||
bool bPhaseGatesAvailable = AITAC_PhaseGatesAvailable(CommanderTeam);
|
||||
|
||||
// Only siege if we have phase gates available
|
||||
if (!bPhaseGatesAvailable) { return nullptr; }
|
||||
|
||||
const AvHAIHiveDefinition* Result = nullptr;
|
||||
float MinDist = 0.0f;
|
||||
|
||||
const vector<AvHAIHiveDefinition> Hives = AITAC_GetAllHives();
|
||||
const vector<AvHAIHiveDefinition*> Hives = AITAC_GetAllHives();
|
||||
|
||||
for (auto it = Hives.begin(); it != Hives.end(); it++)
|
||||
{
|
||||
const AvHAIHiveDefinition* Hive = &(*it);
|
||||
const AvHAIHiveDefinition* Hive = (*it);
|
||||
|
||||
if (it->Status == HIVE_STATUS_UNBUILT) { continue; }
|
||||
|
||||
if (AITAC_GetMarineEligibleToBuildSiege(CommanderTeam, Hive) == nullptr) { continue; }
|
||||
if (Hive->Status == HIVE_STATUS_UNBUILT) { continue; }
|
||||
|
||||
DeployableSearchFilter StructureFilter;
|
||||
StructureFilter.DeployableTypes = STRUCTURE_MARINE_PHASEGATE;
|
||||
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
|
||||
StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||
StructureFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED;
|
||||
StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||
|
||||
AvHAIBuildableStructure* BuiltPhaseGate = AITAC_FindClosestDeployableToLocation(Hive->Location, &StructureFilter);
|
||||
|
||||
// If we have a phase gate already in place, then keep building as long as someone is there. If we don't have a phase gate, only build if there is a marine who isn't sighted by the enemy (to allow element of surprise)
|
||||
if (BuiltPhaseGate)
|
||||
{
|
||||
int NumBuilders = AITAC_GetNumPlayersOfTeamInArea(CommanderTeam, BuiltPhaseGate->Location, UTIL_MetresToGoldSrcUnits(5.0f), false, CommanderBot->Edict, AVH_USER3_COMMANDER_PLAYER);
|
||||
|
||||
if (NumBuilders == 0) { continue; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AITAC_GetMarineEligibleToBuildSiege(CommanderTeam, Hive) == nullptr) { continue; }
|
||||
}
|
||||
|
||||
float ThisDist = vDist2DSq(Hive->FloorLocation, SearchLocation);
|
||||
|
||||
|
@ -820,22 +850,24 @@ const AvHAIHiveDefinition* AICOMM_GetHiveSiegeOpportunityNearestLocation(AvHAIPl
|
|||
|
||||
const AvHAIResourceNode* AICOMM_GetNearestResourceNodeCapOpportunity(const AvHTeamNumber Team, const Vector SearchLocation)
|
||||
{
|
||||
vector<AvHAIResourceNode> AllNodes = AITAC_GetAllResourceNodes();
|
||||
vector<AvHAIResourceNode*> AllNodes = AITAC_GetAllResourceNodes();
|
||||
|
||||
AvHAIResourceNode* Result = nullptr;
|
||||
float MinDist = 0.0f;
|
||||
|
||||
for (auto it = AllNodes.begin(); it != AllNodes.end(); it++)
|
||||
{
|
||||
if (it->bIsOccupied) { continue; }
|
||||
AvHAIResourceNode* ResNode = (*it);
|
||||
|
||||
if (!AITAC_AnyPlayerOnTeamWithLOS(Team, (it->Location + Vector(0.0f, 0.0f, 32.0f)), UTIL_MetresToGoldSrcUnits(5.0f))) { continue; }
|
||||
if (ResNode->bIsOccupied) { continue; }
|
||||
|
||||
float ThisDist = vDist2DSq(it->Location, SearchLocation);
|
||||
if (!AITAC_AnyPlayerOnTeamWithLOS(Team, (ResNode->Location + Vector(0.0f, 0.0f, 32.0f)), UTIL_MetresToGoldSrcUnits(5.0f))) { continue; }
|
||||
|
||||
float ThisDist = vDist2DSq(ResNode->Location, SearchLocation);
|
||||
|
||||
if (!Result || ThisDist < MinDist)
|
||||
{
|
||||
Result = &(*it);
|
||||
Result = ResNode;
|
||||
MinDist = ThisDist;
|
||||
}
|
||||
}
|
||||
|
@ -855,7 +887,7 @@ bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinit
|
|||
|
||||
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(20.0f);
|
||||
|
||||
Vector SiegeLocation;
|
||||
Vector SiegeLocation = ZERO_VECTOR;
|
||||
AvHAIBuildableStructure* ExistingPG = nullptr;
|
||||
|
||||
if (AITAC_PhaseGatesAvailable(CommanderTeam))
|
||||
|
@ -895,7 +927,7 @@ bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinit
|
|||
|
||||
if (FNullEnt(NearestBuilder)) { return false; }
|
||||
|
||||
Vector NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(BUILDING_NAV_MESH), SiegeLocation, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
Vector NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
|
||||
if (!ExistingPG)
|
||||
{
|
||||
|
@ -917,7 +949,7 @@ bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinit
|
|||
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, NextBuildPosition);
|
||||
}
|
||||
|
||||
if (ExistingTF->StructureType != STRUCTURE_MARINE_ADVARMOURY)
|
||||
if (ExistingTF->StructureType != STRUCTURE_MARINE_ADVTURRETFACTORY)
|
||||
{
|
||||
return AICOMM_UpgradeStructure(pBot, ExistingTF);
|
||||
}
|
||||
|
@ -931,7 +963,7 @@ bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinit
|
|||
{
|
||||
SiegeLocation = ExistingTF->Location;
|
||||
|
||||
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(BUILDING_NAV_MESH), SiegeLocation, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
|
||||
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, NextBuildPosition);
|
||||
}
|
||||
|
@ -945,8 +977,98 @@ bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinit
|
|||
|
||||
}
|
||||
|
||||
bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToSiege, commander_action* Action)
|
||||
bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToSecure, commander_action* Action)
|
||||
{
|
||||
DeployableSearchFilter StructureFilter;
|
||||
StructureFilter.DeployableTypes = STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY | STRUCTURE_MARINE_PHASEGATE;
|
||||
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
||||
StructureFilter.DeployableTeam = pBot->Player->GetTeam();
|
||||
StructureFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
|
||||
StructureFilter.ReachabilityTeam = pBot->Player->GetTeam();
|
||||
StructureFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING;
|
||||
|
||||
AvHAIBuildableStructure* ExistingStructure = AITAC_FindClosestDeployableToLocation(HiveToSecure->FloorLocation, &StructureFilter);
|
||||
AvHAIBuildableStructure* ExistingPG = nullptr;
|
||||
AvHAIBuildableStructure* ExistingTF = nullptr;
|
||||
|
||||
Vector OutpostLocation = (ExistingStructure) ? ExistingStructure->Location : HiveToSecure->FloorLocation;
|
||||
|
||||
if (ExistingStructure)
|
||||
{
|
||||
if (ExistingStructure->StructureType == STRUCTURE_MARINE_PHASEGATE)
|
||||
{
|
||||
ExistingPG = ExistingStructure;
|
||||
}
|
||||
else
|
||||
{
|
||||
ExistingTF = ExistingStructure;
|
||||
}
|
||||
}
|
||||
|
||||
if (AITAC_PhaseGatesAvailable(pBot->Player->GetTeam()))
|
||||
{
|
||||
if (!ExistingPG)
|
||||
{
|
||||
StructureFilter.DeployableTypes = STRUCTURE_MARINE_PHASEGATE;
|
||||
|
||||
ExistingPG = AITAC_FindClosestDeployableToLocation(OutpostLocation, &StructureFilter);
|
||||
|
||||
if (!ExistingPG)
|
||||
{
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), OutpostLocation, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
if (!vIsZero(BuildLocation))
|
||||
{
|
||||
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ExistingTF)
|
||||
{
|
||||
StructureFilter.DeployableTypes = STRUCTURE_MARINE_TURRETFACTORY;
|
||||
|
||||
ExistingTF = AITAC_FindClosestDeployableToLocation(OutpostLocation, &StructureFilter);
|
||||
|
||||
if (!ExistingTF)
|
||||
{
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), OutpostLocation, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
|
||||
if (!vIsZero(BuildLocation))
|
||||
{
|
||||
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
StructureFilter.DeployableTypes = STRUCTURE_MARINE_TURRET;
|
||||
StructureFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
||||
|
||||
int NumTurrets = AITAC_GetNumDeployablesNearLocation(ExistingTF->Location, &StructureFilter);
|
||||
|
||||
if (NumTurrets < 5)
|
||||
{
|
||||
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingTF->Location, UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
|
||||
if (!vIsZero(BuildLocation))
|
||||
{
|
||||
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!UTIL_IsStructureElectrified(ExistingTF->edict))
|
||||
{
|
||||
return AICOMM_ResearchTech(pBot, ExistingTF, RESEARCH_ELECTRICAL);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -958,7 +1080,7 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair, commander
|
|||
|
||||
DeployableSearchFilter ExistingPortalFilter;
|
||||
ExistingPortalFilter.DeployableTypes = STRUCTURE_MARINE_INFANTRYPORTAL;
|
||||
ExistingPortalFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(5.0f);
|
||||
ExistingPortalFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f);
|
||||
ExistingPortalFilter.DeployableTeam = pBot->Player->GetTeam();
|
||||
ExistingPortalFilter.ReachabilityFlags = AI_REACHABILITY_MARINE;
|
||||
ExistingPortalFilter.ReachabilityTeam = pBot->Player->GetTeam();
|
||||
|
@ -968,7 +1090,7 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair, commander
|
|||
// First see if we can place the next infantry portal next to the first one
|
||||
if (ExistingInfantryPortal)
|
||||
{
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInDonut(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), ExistingInfantryPortal->edict->v.origin, UTIL_MetresToGoldSrcUnits(2.0f), UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInDonutIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingInfantryPortal->edict->v.origin, UTIL_MetresToGoldSrcUnits(2.0f), UTIL_MetresToGoldSrcUnits(3.0f));
|
||||
}
|
||||
|
||||
if (vIsZero(BuildLocation))
|
||||
|
@ -997,12 +1119,12 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair, commander
|
|||
float Distance = vDist2D(NearestPointToChair, CommChair->v.origin);
|
||||
float RandomDist = UTIL_MetresToGoldSrcUnits(5.0f) - Distance;
|
||||
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), NearestPointToChair, RandomDist);
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestPointToChair, RandomDist);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), CommChair->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1011,6 +1133,25 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair, commander
|
|||
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation);
|
||||
}
|
||||
|
||||
bool AICOMM_CheckForNextRecycleAction(AvHAIPlayer* pBot)
|
||||
{
|
||||
DeployableSearchFilter UnreachableFilter;
|
||||
UnreachableFilter.DeployableTeam = pBot->Player->GetTeam();
|
||||
UnreachableFilter.ReachabilityTeam = pBot->Player->GetTeam();
|
||||
UnreachableFilter.ReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
UnreachableFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING | STRUCTURE_STATUS_RESEARCHING;
|
||||
|
||||
AvHAIBuildableStructure* UnreachableStructure = AITAC_FindClosestDeployableToLocation(AITAC_GetCommChairLocation(pBot->Player->GetTeam()), &UnreachableFilter);
|
||||
|
||||
// Recycle any structures which are unreachable (e.g. sunk below the map)
|
||||
if (UnreachableStructure)
|
||||
{
|
||||
return AICOMM_RecycleStructure(pBot, UnreachableStructure);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
|
||||
{
|
||||
AICOMM_CheckNewRequests(pBot);
|
||||
|
@ -1245,6 +1386,7 @@ void AICOMM_CommanderThink(AvHAIPlayer* pBot)
|
|||
|
||||
if (gpGlobals->time < pBot->next_commander_action_time) { return; }
|
||||
|
||||
if (AICOMM_CheckForNextRecycleAction(pBot)) { return; }
|
||||
if (AICOMM_CheckForNextSupportAction(pBot)) { return; }
|
||||
if (AICOMM_CheckForNextBuildAction(pBot, &pBot->BuildAction)) { return; }
|
||||
if (AICOMM_CheckForNextResearchAction(pBot, &pBot->ResearchAction)) { return; }
|
||||
|
@ -1320,11 +1462,11 @@ const AvHAIHiveDefinition* AICOMM_GetEmptyHiveOpportunityNearestLocation(AvHAIPl
|
|||
const AvHAIHiveDefinition* Result = nullptr;
|
||||
float MinDist = 0.0f;
|
||||
|
||||
const vector<AvHAIHiveDefinition> Hives = AITAC_GetAllHives();
|
||||
const vector<AvHAIHiveDefinition*> Hives = AITAC_GetAllHives();
|
||||
|
||||
for (auto it = Hives.begin(); it != Hives.end(); it++)
|
||||
{
|
||||
const AvHAIHiveDefinition* Hive = &(*it);
|
||||
const AvHAIHiveDefinition* Hive = (*it);
|
||||
|
||||
if (Hive->Status != HIVE_STATUS_UNBUILT) { continue; }
|
||||
|
||||
|
@ -1332,7 +1474,7 @@ const AvHAIHiveDefinition* AICOMM_GetEmptyHiveOpportunityNearestLocation(AvHAIPl
|
|||
|
||||
if (AITAC_GetNearestHiddenPlayerInLocation(CommanderTeam, Hive->Location, UTIL_MetresToGoldSrcUnits(10.0f)) == nullptr) { continue; }
|
||||
|
||||
if (!AITAC_AnyPlayerOnTeamWithLOS(CommanderTeam, Hive->Location, UTIL_MetresToGoldSrcUnits(10.0f)))
|
||||
if (AITAC_AnyPlayerOnTeamWithLOS(CommanderTeam, Hive->Location, UTIL_MetresToGoldSrcUnits(10.0f)))
|
||||
{
|
||||
DeployableSearchFilter StructureFilter;
|
||||
StructureFilter.DeployableTeam = CommanderTeam;
|
||||
|
@ -1345,7 +1487,7 @@ const AvHAIHiveDefinition* AICOMM_GetEmptyHiveOpportunityNearestLocation(AvHAIPl
|
|||
|
||||
AvHAIBuildableStructure* PG = AITAC_FindClosestDeployableToLocation(Hive->FloorLocation, &StructureFilter);
|
||||
|
||||
bool bCanSeePG = (PG && AITAC_AnyPlayerOnTeamWithLOS(CommanderTeam, UTIL_GetCentreOfEntity(PG->edict), UTIL_MetresToGoldSrcUnits(10.0f)));
|
||||
bool bCanSeePG = (!PG || AITAC_AnyPlayerOnTeamWithLOS(CommanderTeam, UTIL_GetCentreOfEntity(PG->edict), UTIL_MetresToGoldSrcUnits(10.0f)));
|
||||
|
||||
if (!bCanSeePG)
|
||||
{
|
||||
|
@ -1363,7 +1505,7 @@ const AvHAIHiveDefinition* AICOMM_GetEmptyHiveOpportunityNearestLocation(AvHAIPl
|
|||
bNeedsElectrifying = (UTIL_StructureIsFullyBuilt(TF->edict) && !UTIL_IsStructureElectrified(TF->edict) && AITAC_DeployableExistsAtLocation(TF->Location, &StructureFilter));
|
||||
}
|
||||
|
||||
bool bCanSeeTF = (TF && AITAC_AnyPlayerOnTeamWithLOS(CommanderTeam, UTIL_GetCentreOfEntity(TF->edict), UTIL_MetresToGoldSrcUnits(10.0f)));
|
||||
bool bCanSeeTF = (!TF || AITAC_AnyPlayerOnTeamWithLOS(CommanderTeam, UTIL_GetCentreOfEntity(TF->edict), UTIL_MetresToGoldSrcUnits(10.0f)));
|
||||
|
||||
if (!bNeedsElectrifying && !bCanSeePG && !bCanSeeTF) { continue; }
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ bool AICOMM_IssueSecureResNodeOrder(AvHAIPlayer* pBot, edict_t* Recipient, const
|
|||
void AICOMM_ClearAction(commander_action* Action);
|
||||
bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot, commander_action* Action);
|
||||
bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot);
|
||||
bool AICOMM_CheckForNextRecycleAction(AvHAIPlayer* pBot);
|
||||
bool AICOMM_CheckForNextResearchAction(AvHAIPlayer* pBot, commander_action* Action);
|
||||
void AICOMM_SetDropHealthAction(AvHAIPlayer* pBot, commander_action* Action, edict_t* Recipient);
|
||||
void AICOMM_SetDropAmmoAction(AvHAIPlayer* pBot, commander_action* Action, edict_t* Recipient);
|
||||
|
@ -39,7 +40,7 @@ const AvHAIHiveDefinition* AICOMM_GetEmptyHiveOpportunityNearestLocation(AvHAIPl
|
|||
|
||||
bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair, commander_action* Action);
|
||||
bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToSiege, commander_action* Action);
|
||||
bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToSiege, commander_action* Action);
|
||||
bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinition* HiveToSecure, commander_action* Action);
|
||||
|
||||
ai_commander_request* AICOMM_GetExistingRequestForPlayer(AvHAIPlayer* pBot, edict_t* Requestor);
|
||||
void AICOMM_CheckNewRequests(AvHAIPlayer* pBot);
|
||||
|
|
|
@ -89,6 +89,7 @@ typedef enum _AI_REACHABILITY_STATUS
|
|||
AI_REACHABILITY_GORGE = 1u << 2,
|
||||
AI_REACHABILITY_ONOS = 1u << 3,
|
||||
AI_REACHABILITY_WELDER = 1u << 4,
|
||||
AI_REACHABILITY_UNREACHABLE = 1u << 5,
|
||||
|
||||
AI_REACHABILITY_ALL = -1
|
||||
} AvHAIReachabilityStatus;
|
||||
|
@ -179,6 +180,12 @@ typedef struct _OFF_MESH_CONN
|
|||
edict_t* TargetObject = nullptr;
|
||||
} AvHAIOffMeshConnection;
|
||||
|
||||
typedef struct _STRUCTURE_OBSTACLE
|
||||
{
|
||||
unsigned int NavMeshIndex = 0;
|
||||
unsigned int ObstacleRef = 0;
|
||||
} AvHAITempObstacle;
|
||||
|
||||
// Data structure used to track resource nodes in the map
|
||||
typedef struct _RESOURCE_NODE
|
||||
{
|
||||
|
@ -266,7 +273,7 @@ typedef struct _AVH_AI_BUILDABLE_STRUCTURE
|
|||
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[MAX_NAV_MESHES]; // References to this structure's obstacles across each nav mesh
|
||||
vector< AvHAITempObstacle> Obstacles;
|
||||
vector<AvHAIOffMeshConnection> OffMeshConnections; // References to any off-mesh connections this structure is associated with
|
||||
Vector LastSuccessfulCommanderLocation = g_vecZero; // Tracks the last commander view location where it successfully placed or selected the building
|
||||
Vector LastSuccessfulCommanderAngle = g_vecZero; // Tracks the last commander input angle ("click" location) used to successfully place or select building
|
||||
|
|
|
@ -418,31 +418,97 @@ Vector UTIL_GetNearestPointOnNavWall(const nav_profile &NavProfile, const Vector
|
|||
return g_vecZero;
|
||||
}
|
||||
|
||||
unsigned int UTIL_AddTemporaryObstacle(const Vector Location, float Radius, float Height, int area)
|
||||
unsigned int UTIL_AddTemporaryObstacle(unsigned int NavMeshIndex, const Vector Location, float Radius, float Height, int area)
|
||||
{
|
||||
unsigned int ObstacleNum = 0;
|
||||
|
||||
float Pos[3] = { Location.x, Location.z - (Height * 0.5f), -Location.y };
|
||||
|
||||
for (int i = 0; i < MAX_NAV_MESHES; i++)
|
||||
|
||||
if (NavMeshes[NavMeshIndex].tileCache)
|
||||
{
|
||||
if (NavMeshes[i].tileCache)
|
||||
float Pos[3] = { Location.x, Location.z - (Height * 0.5f), -Location.y };
|
||||
|
||||
dtObstacleRef ObsRef = 0;
|
||||
NavMeshes[NavMeshIndex].tileCache->addObstacle(Pos, Radius, Height, area, &ObsRef);
|
||||
|
||||
ObstacleNum = (unsigned int)ObsRef;
|
||||
|
||||
if (ObstacleNum > 0)
|
||||
{
|
||||
dtObstacleRef ObsRef = 0;
|
||||
NavMeshes[i].tileCache->addObstacle(Pos, Radius, Height, area, &ObsRef);
|
||||
|
||||
ObstacleNum = (unsigned int)ObsRef;
|
||||
|
||||
if (area == DT_TILECACHE_NULL_AREA || area == DT_TILECACHE_WELD_AREA)
|
||||
{
|
||||
bNavMeshModified = true;
|
||||
}
|
||||
bNavMeshModified = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ObstacleNum;
|
||||
}
|
||||
|
||||
void UTIL_AddStructureTemporaryObstacles(AvHAIBuildableStructure* Structure)
|
||||
{
|
||||
bool bCollideWithPlayers = UTIL_ShouldStructureCollide(Structure->StructureType);
|
||||
|
||||
float Radius = UTIL_GetStructureRadiusForObstruction(Structure->StructureType);
|
||||
|
||||
// Not all structures collide with players (e.g. phase gate)
|
||||
if (bCollideWithPlayers)
|
||||
{
|
||||
unsigned int area = UTIL_GetAreaForObstruction(Structure->StructureType, Structure->edict);
|
||||
|
||||
// We add an obstacle for the building nav mesh below
|
||||
for (int i = 0; i < BUILDING_NAV_MESH; i++)
|
||||
{
|
||||
unsigned int NewObstacleRef = UTIL_AddTemporaryObstacle(i, UTIL_GetCentreOfEntity(Structure->edict), Radius, 100.0f, area);
|
||||
|
||||
if (NewObstacleRef > 0)
|
||||
{
|
||||
AvHAITempObstacle NewObstacle;
|
||||
NewObstacle.NavMeshIndex = i;
|
||||
NewObstacle.ObstacleRef = NewObstacleRef;
|
||||
|
||||
Structure->Obstacles.push_back(NewObstacle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Always cut a hole in the building nav mesh so we don't try to place anything on top of this structure in future
|
||||
unsigned int NewObstacleRef = UTIL_AddTemporaryObstacle(BUILDING_NAV_MESH, UTIL_GetCentreOfEntity(Structure->edict), Radius * 1.5f, 100.0f, DT_TILECACHE_NULL_AREA);
|
||||
|
||||
if (NewObstacleRef > 0)
|
||||
{
|
||||
AvHAITempObstacle NewObstacle;
|
||||
NewObstacle.NavMeshIndex = BUILDING_NAV_MESH;
|
||||
NewObstacle.ObstacleRef = NewObstacleRef;
|
||||
|
||||
Structure->Obstacles.push_back(NewObstacle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void UTIL_RemoveStructureTemporaryObstacles(AvHAIBuildableStructure* Structure)
|
||||
{
|
||||
for (auto it = Structure->Obstacles.begin(); it != Structure->Obstacles.end();)
|
||||
{
|
||||
int NavMeshIndex = it->NavMeshIndex;
|
||||
|
||||
if (NavMeshes[NavMeshIndex].tileCache)
|
||||
{
|
||||
const dtTileCacheObstacle* ObstacleToRemove = NavMeshes[NavMeshIndex].tileCache->getObstacleByRef((dtObstacleRef)it->ObstacleRef);
|
||||
|
||||
if (ObstacleToRemove)
|
||||
{
|
||||
dtStatus RemovalStatus = NavMeshes[NavMeshIndex].tileCache->removeObstacle((dtObstacleRef)it->ObstacleRef);
|
||||
|
||||
if (dtStatusSucceed(RemovalStatus))
|
||||
{
|
||||
bNavMeshModified = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
it = Structure->Obstacles.erase(it);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void UTIL_AddTemporaryObstacles(const Vector Location, float Radius, float Height, int area, unsigned int* ObstacleRefArray)
|
||||
{
|
||||
unsigned int ObstacleNum = 0;
|
||||
|
@ -460,7 +526,7 @@ void UTIL_AddTemporaryObstacles(const Vector Location, float Radius, float Heigh
|
|||
|
||||
ObstacleRefArray[i] = (unsigned int)ObsRef;
|
||||
|
||||
if (area == DT_TILECACHE_NULL_AREA || area == DT_TILECACHE_WELD_AREA)
|
||||
if (ObstacleNum > 0)
|
||||
{
|
||||
bNavMeshModified = true;
|
||||
}
|
||||
|
|
|
@ -154,9 +154,9 @@ static const float pReachableExtents[3] = { max_ai_use_reach, max_ai_use_reach,
|
|||
|
||||
static const int MAX_NAV_PROFILES = 16; // Max number of possible nav profiles. Currently 9 are used (see top of this header file)
|
||||
|
||||
static const int REGULAR_NAV_MESH = 0;
|
||||
static const int ONOS_NAV_MESH = 1;
|
||||
static const int BUILDING_NAV_MESH = 2;
|
||||
static const int REGULAR_NAV_MESH = 0; // Nav mesh used by all players except Onos and the AI commander
|
||||
static const int ONOS_NAV_MESH = 1; // Nav mesh used by Onos (due to larger hitbox)
|
||||
static const int BUILDING_NAV_MESH = 2; // Nav mesh used by commander for building placement. Must be the last nav mesh index (see UTIL_AddStructureTemporaryObstacles)
|
||||
|
||||
static const int DT_AREA_NULL = 0; // Represents a null area on the nav mesh. Not traversable and considered not on the nav mesh
|
||||
static const int DT_AREA_BLOCKED = 3; // Area occupied by an obstruction (e.g. building). Not traversable, but considered to be on the nav mesh
|
||||
|
@ -302,9 +302,10 @@ Vector UTIL_GetNearestPointOnNavWall(const nav_profile& NavProfile, const Vector
|
|||
An example use case is to place an obstacle of area type SAMPLE_POLYAREA_OBSTRUCTION to mark where buildings are.
|
||||
Using DT_AREA_NULL will effectively cut a hole in the nav mesh, meaning it's no longer considered a valid mesh position.
|
||||
*/
|
||||
unsigned int UTIL_AddTemporaryObstacle(const Vector Location, float Radius, float Height, int area);
|
||||
unsigned int UTIL_AddTemporaryObstacle(unsigned int NavMeshIndex, const Vector Location, float Radius, float Height, int area);
|
||||
void UTIL_AddTemporaryObstacles(const Vector Location, float Radius, float Height, int area, unsigned int* ObstacleRefArray);
|
||||
|
||||
void UTIL_AddStructureTemporaryObstacles(AvHAIBuildableStructure* Structure);
|
||||
void UTIL_RemoveStructureTemporaryObstacles(AvHAIBuildableStructure* Structure);
|
||||
|
||||
unsigned int UTIL_AddTemporaryBoxObstacle(Vector bMin, Vector bMax, int area);
|
||||
|
||||
|
|
|
@ -1597,6 +1597,9 @@ void BotStopCommanderMode(AvHAIPlayer* pBot)
|
|||
|
||||
if (IsPlayerCommander(pBot->Edict))
|
||||
{
|
||||
CLIENT_COMMAND(pBot->Edict, "stopcommandermode");
|
||||
pBot->Player->SetUser3(AVH_USER3_MARINE_PLAYER);
|
||||
|
||||
// Cheesy way to make sure player class change is sent to everyone
|
||||
pBot->Player->EffectivePlayerClassChanged();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -811,8 +811,8 @@ void AITAC_RefreshReachabilityForItem(AvHAIDroppedItem* Item)
|
|||
|
||||
if (!bOnNavMesh)
|
||||
{
|
||||
Item->TeamAReachabilityFlags = AI_REACHABILITY_NONE;
|
||||
Item->TeamBReachabilityFlags = AI_REACHABILITY_NONE;
|
||||
Item->TeamAReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
Item->TeamBReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -838,6 +838,10 @@ void AITAC_RefreshReachabilityForItem(AvHAIDroppedItem* Item)
|
|||
{
|
||||
Item->TeamAReachabilityFlags |= AI_REACHABILITY_WELDER;
|
||||
}
|
||||
else
|
||||
{
|
||||
Item->TeamAReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -863,6 +867,10 @@ void AITAC_RefreshReachabilityForItem(AvHAIDroppedItem* Item)
|
|||
{
|
||||
Item->TeamBReachabilityFlags |= AI_REACHABILITY_WELDER;
|
||||
}
|
||||
else
|
||||
{
|
||||
Item->TeamBReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -896,8 +904,8 @@ void AITAC_RefreshReachabilityForResNode(AvHAIResourceNode* ResNode)
|
|||
|
||||
if (!bOnNavMesh)
|
||||
{
|
||||
ResNode->TeamAReachabilityFlags = AI_REACHABILITY_NONE;
|
||||
ResNode->TeamBReachabilityFlags = AI_REACHABILITY_NONE;
|
||||
ResNode->TeamAReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
ResNode->TeamBReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -926,6 +934,10 @@ void AITAC_RefreshReachabilityForResNode(AvHAIResourceNode* ResNode)
|
|||
{
|
||||
ResNode->TeamAReachabilityFlags |= AI_REACHABILITY_WELDER;
|
||||
}
|
||||
else
|
||||
{
|
||||
ResNode->TeamAReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -948,6 +960,11 @@ void AITAC_RefreshReachabilityForResNode(AvHAIResourceNode* ResNode)
|
|||
{
|
||||
ResNode->TeamAReachabilityFlags |= AI_REACHABILITY_ONOS;
|
||||
}
|
||||
|
||||
if (ResNode->TeamAReachabilityFlags == AI_REACHABILITY_NONE)
|
||||
{
|
||||
ResNode->TeamAReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetGameRules()->GetTeamB()->GetTeamType() == AVH_CLASS_TYPE_MARINE)
|
||||
|
@ -972,6 +989,10 @@ void AITAC_RefreshReachabilityForResNode(AvHAIResourceNode* ResNode)
|
|||
{
|
||||
ResNode->TeamBReachabilityFlags |= AI_REACHABILITY_WELDER;
|
||||
}
|
||||
else
|
||||
{
|
||||
ResNode->TeamBReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -994,6 +1015,11 @@ void AITAC_RefreshReachabilityForResNode(AvHAIResourceNode* ResNode)
|
|||
{
|
||||
ResNode->TeamBReachabilityFlags |= AI_REACHABILITY_ONOS;
|
||||
}
|
||||
|
||||
if (ResNode->TeamBReachabilityFlags == AI_REACHABILITY_NONE)
|
||||
{
|
||||
ResNode->TeamBReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1274,7 +1300,6 @@ void AITAC_RefreshBuildableStructures()
|
|||
if (it->second.LastSeen < StructureRefreshFrame)
|
||||
{
|
||||
AITAC_OnStructureDestroyed(&it->second);
|
||||
UTIL_RemoveTemporaryObstacles(it->second.ObstacleRefs);
|
||||
it = TeamAStructureMap.erase(it);
|
||||
}
|
||||
else
|
||||
|
@ -1293,7 +1318,6 @@ void AITAC_RefreshBuildableStructures()
|
|||
if (it->second.LastSeen < StructureRefreshFrame)
|
||||
{
|
||||
AITAC_OnStructureDestroyed(&it->second);
|
||||
UTIL_RemoveTemporaryObstacles(it->second.ObstacleRefs);
|
||||
it = TeamBStructureMap.erase(it);
|
||||
}
|
||||
else
|
||||
|
@ -1476,12 +1500,15 @@ void AITAC_RefreshReachabilityForStructure(AvHAIBuildableStructure* Structure)
|
|||
|
||||
Structure->bReachabilityMarkedDirty = false;
|
||||
|
||||
Structure->TeamAReachabilityFlags = AI_REACHABILITY_NONE;
|
||||
Structure->TeamBReachabilityFlags = AI_REACHABILITY_NONE;
|
||||
|
||||
bool bIsOnNavMesh = UTIL_PointIsOnNavmesh(BaseNavProfiles[MARINE_BASE_NAV_PROFILE], UTIL_GetEntityGroundLocation(Structure->edict), Vector(max_player_use_reach, max_player_use_reach, max_player_use_reach));
|
||||
|
||||
if (!bIsOnNavMesh)
|
||||
{
|
||||
Structure->TeamAReachabilityFlags = AI_REACHABILITY_NONE;
|
||||
Structure->TeamBReachabilityFlags = AI_REACHABILITY_NONE;
|
||||
Structure->TeamAReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
Structure->TeamBReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1508,6 +1535,10 @@ void AITAC_RefreshReachabilityForStructure(AvHAIBuildableStructure* Structure)
|
|||
{
|
||||
Structure->TeamAReachabilityFlags |= AI_REACHABILITY_WELDER;
|
||||
}
|
||||
else
|
||||
{
|
||||
Structure->TeamAReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1530,6 +1561,11 @@ void AITAC_RefreshReachabilityForStructure(AvHAIBuildableStructure* Structure)
|
|||
{
|
||||
Structure->TeamAReachabilityFlags |= AI_REACHABILITY_ONOS;
|
||||
}
|
||||
|
||||
if (Structure->TeamAReachabilityFlags == AI_REACHABILITY_NONE)
|
||||
{
|
||||
Structure->TeamAReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetGameRules()->GetTeamB()->GetTeamType() == AVH_CLASS_TYPE_MARINE)
|
||||
|
@ -1555,6 +1591,10 @@ void AITAC_RefreshReachabilityForStructure(AvHAIBuildableStructure* Structure)
|
|||
{
|
||||
Structure->TeamBReachabilityFlags |= AI_REACHABILITY_WELDER;
|
||||
}
|
||||
else
|
||||
{
|
||||
Structure->TeamBReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1577,6 +1617,11 @@ void AITAC_RefreshReachabilityForStructure(AvHAIBuildableStructure* Structure)
|
|||
{
|
||||
Structure->TeamBReachabilityFlags |= AI_REACHABILITY_ONOS;
|
||||
}
|
||||
|
||||
if (Structure->TeamBReachabilityFlags == AI_REACHABILITY_NONE)
|
||||
{
|
||||
Structure->TeamBReachabilityFlags = AI_REACHABILITY_UNREACHABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1602,29 +1647,16 @@ void AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
|
|||
|
||||
std::unordered_map<int, AvHAIBuildableStructure>& BuildingMap = (BaseBuildable->GetTeamNumber() == TeamANumber) ? TeamAStructureMap : TeamBStructureMap;
|
||||
|
||||
// This is the first time we've seen this structure, so it must be new
|
||||
if (BuildingMap[EntIndex].LastSeen == 0)
|
||||
{
|
||||
BuildingMap[EntIndex].EntityRef = BaseBuildable;
|
||||
BuildingMap[EntIndex].edict = BuildingEdict;
|
||||
|
||||
BuildingMap[EntIndex].OffMeshConnections.clear();
|
||||
BuildingMap[EntIndex].Obstacles.clear();
|
||||
|
||||
memset(&BuildingMap[EntIndex].ObstacleRefs, 0, sizeof(BuildingMap[EntIndex].ObstacleRefs));
|
||||
|
||||
bool bShouldCollide = UTIL_ShouldStructureCollide(StructureType);
|
||||
|
||||
if (bShouldCollide)
|
||||
{
|
||||
unsigned int area = UTIL_GetAreaForObstruction(StructureType, BuildingEdict);
|
||||
float Radius = UTIL_GetStructureRadiusForObstruction(StructureType);
|
||||
UTIL_AddTemporaryObstacles(UTIL_GetCentreOfEntity(BuildingMap[EntIndex].edict), Radius, 100.0f, area, BuildingMap[EntIndex].ObstacleRefs);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(BuildingMap[EntIndex].ObstacleRefs, 0, sizeof(unsigned int) * MAX_NAV_MESHES);
|
||||
}
|
||||
|
||||
BuildingMap[EntIndex].Location = g_vecZero;
|
||||
BuildingMap[EntIndex].Location = g_vecZero; // We set this just below after calculating reachability
|
||||
|
||||
AITAC_OnStructureCreated(&BuildingMap[EntIndex]);
|
||||
}
|
||||
|
@ -1695,8 +1727,12 @@ void AITAC_OnStructureCreated(AvHAIBuildableStructure* NewStructure)
|
|||
{
|
||||
if (!GetGameRules()->GetGameStarted()) { return; }
|
||||
|
||||
UTIL_AddStructureTemporaryObstacles(NewStructure);
|
||||
|
||||
AvHTeamNumber StructureTeam = NewStructure->EntityRef->GetTeamNumber();
|
||||
|
||||
AITAC_RefreshReachabilityForStructure(NewStructure);
|
||||
|
||||
if (StructureTeam == TEAM_IND) { return; }
|
||||
|
||||
AvHTeam* Team = GetGameRules()->GetTeam(StructureTeam);
|
||||
|
@ -1791,6 +1827,8 @@ void AITAC_OnStructureBeginRecycling(AvHAIBuildableStructure* RecyclingStructure
|
|||
|
||||
void AITAC_OnStructureDestroyed(AvHAIBuildableStructure* DestroyedStructure)
|
||||
{
|
||||
UTIL_RemoveStructureTemporaryObstacles(DestroyedStructure);
|
||||
|
||||
if (DestroyedStructure->StructureType == STRUCTURE_MARINE_PHASEGATE)
|
||||
{
|
||||
// Eliminate all connections from this phase gate
|
||||
|
@ -3050,14 +3088,28 @@ vector<AvHPlayer*> AITAC_GetAllPlayersOnTeam(AvHTeamNumber Team)
|
|||
return Result;
|
||||
}
|
||||
|
||||
const vector<AvHAIResourceNode>& AITAC_GetAllResourceNodes()
|
||||
const vector<AvHAIResourceNode*> AITAC_GetAllResourceNodes()
|
||||
{
|
||||
return ResourceNodes;
|
||||
vector<AvHAIResourceNode*> Results;
|
||||
|
||||
for (auto it = ResourceNodes.begin(); it != ResourceNodes.end(); it++)
|
||||
{
|
||||
Results.push_back(&(*it));
|
||||
}
|
||||
|
||||
return Results;
|
||||
}
|
||||
|
||||
const vector<AvHAIHiveDefinition>& AITAC_GetAllHives()
|
||||
const vector<AvHAIHiveDefinition*> AITAC_GetAllHives()
|
||||
{
|
||||
return Hives;
|
||||
vector<AvHAIHiveDefinition*> Results;
|
||||
|
||||
for (auto it = Hives.begin(); it != Hives.end(); it++)
|
||||
{
|
||||
Results.push_back(&(*it));
|
||||
}
|
||||
|
||||
return Results;
|
||||
}
|
||||
|
||||
bool AITAC_AnyPlayerOnTeamWithLOS(AvHTeamNumber Team, const Vector& Location, float SearchRadius)
|
||||
|
|
|
@ -145,8 +145,8 @@ edict_t* AITAC_GetMarineEligibleToBuildSiege(AvHTeamNumber Team, const AvHAIHive
|
|||
vector<AvHPlayer*> AITAC_GetAllPlayersOnTeam(AvHTeamNumber Team);
|
||||
edict_t* AITAC_GetNearestHiddenPlayerInLocation(AvHTeamNumber Team, const Vector Location, const float MaxRadius);
|
||||
|
||||
const vector<AvHAIResourceNode>& AITAC_GetAllResourceNodes();
|
||||
const vector<AvHAIHiveDefinition>& AITAC_GetAllHives();
|
||||
const vector<AvHAIResourceNode*> AITAC_GetAllResourceNodes();
|
||||
const vector<AvHAIHiveDefinition*> AITAC_GetAllHives();
|
||||
|
||||
bool AITAC_AnyPlayerOnTeamWithLOS(AvHTeamNumber Team, const Vector& Location, float SearchRadius);
|
||||
|
||||
|
|
|
@ -487,6 +487,8 @@ public:
|
|||
|
||||
bool GetHasSeenATeam();
|
||||
|
||||
bool GetPurchaseAllowed(AvHMessageID inUpgrade, int& outCost, string* outErrorMessage = NULL) const;
|
||||
|
||||
void GiveOrderToSelection(AvHOrder& inOrder);
|
||||
private:
|
||||
void AcquireOverwatchTarget();
|
||||
|
@ -505,7 +507,7 @@ private:
|
|||
bool QueryEnemySighted(CBaseEntity* inEntity);
|
||||
bool GetHasActiveAlienWeaponWithImpulse(AvHMessageID inMessageID) const;
|
||||
bool GetRandomGameStartedTick(float inApproximateFrameRate);
|
||||
bool GetPurchaseAllowed(AvHMessageID inUpgrade, int& outCost, string* outErrorMessage = NULL) const;
|
||||
|
||||
int GetRelevantWeight(void) const;
|
||||
int GetRelevantWeightForWeapon(AvHBasePlayerWeapon* inWeapon) const;
|
||||
void GetSpeeds(int& outBaseSpeed, int& outUnemcumberedSpeed) const;
|
||||
|
|
Loading…
Reference in a new issue