Started base system

* Commanders now think in terms of establishing and building bases rather than placing individual structures. Should help reduce duplication of structures, selling structures unnecessarily etc.
* Incomplete implementation: not currently used but will be once finished
This commit is contained in:
RGreenlees 2024-06-05 20:32:15 +01:00 committed by pierow
parent 73ff332b68
commit 0897cf15a0
8 changed files with 754 additions and 124 deletions

View file

@ -13,9 +13,9 @@
#include "AvHSharedUtil.h" #include "AvHSharedUtil.h"
#include "AvHServerUtil.h" #include "AvHServerUtil.h"
bool AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureType StructureToDeploy, const Vector Location, StructurePurpose Purpose) AvHAIBuildableStructure* AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureType StructureToDeploy, const Vector Location, StructurePurpose Purpose, bool bPlacedByHuman)
{ {
if (vIsZero(Location)) { return false; } if (vIsZero(Location)) { return nullptr; }
nav_profile WelderProfile = GetBaseNavProfile(MARINE_BASE_NAV_PROFILE); nav_profile WelderProfile = GetBaseNavProfile(MARINE_BASE_NAV_PROFILE);
WelderProfile.Filters.addIncludeFlags(SAMPLE_POLYFLAGS_WELD); WelderProfile.Filters.addIncludeFlags(SAMPLE_POLYFLAGS_WELD);
@ -34,31 +34,32 @@ bool AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureTyp
// This would be rejected if a human was trying to build here, so don't let the bot do it // This would be rejected if a human was trying to build here, so don't let the bot do it
if (!AvHSHUGetIsSiteValidForBuild(StructureID, &BuildLocation)) if (!AvHSHUGetIsSiteValidForBuild(StructureID, &BuildLocation))
{ {
return false; return nullptr;
} }
string theErrorMessage; string theErrorMessage;
int theCost = 0; int theCost = 0;
bool thePurchaseAllowed = pBot->Player->GetPurchaseAllowed(StructureID, theCost, &theErrorMessage); bool thePurchaseAllowed = pBot->Player->GetPurchaseAllowed(StructureID, theCost, &theErrorMessage);
if (!thePurchaseAllowed) { return false; } if (!thePurchaseAllowed) { return nullptr; }
CBaseEntity* NewStructureEntity = AvHSUBuildTechForPlayer(StructureID, BuildLocation, pBot->Player); CBaseEntity* NewStructureEntity = AvHSUBuildTechForPlayer(StructureID, BuildLocation, pBot->Player);
if (!NewStructureEntity) { return false; } if (!NewStructureEntity) { return nullptr; }
AvHAIBuildableStructure* NewStructure = AITAC_UpdateBuildableStructure(NewStructureEntity); AvHAIBuildableStructure* NewStructure = AITAC_UpdateBuildableStructure(NewStructureEntity);
if (NewStructure) if (NewStructure)
{ {
NewStructure->Purpose = Purpose; NewStructure->Purpose = Purpose;
NewStructure->bPlacedByHuman = bPlacedByHuman;
} }
pBot->Player->PayPurchaseCost(theCost); pBot->Player->PayPurchaseCost(theCost);
pBot->next_commander_action_time = gpGlobals->time + 1.0f; pBot->next_commander_action_time = gpGlobals->time + 1.0f;
return true; return NewStructure;
} }
bool AICOMM_DeployItem(AvHAIPlayer* pBot, const AvHAIDeployableItemType ItemToDeploy, const Vector Location) bool AICOMM_DeployItem(AvHAIPlayer* pBot, const AvHAIDeployableItemType ItemToDeploy, const Vector Location)
@ -1049,9 +1050,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase) if (!bEnemyInBase)
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
} }
@ -1069,9 +1070,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase) if (!bEnemyInBase)
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
} }
} }
@ -1084,9 +1085,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase) if (!bEnemyInBase)
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMOURY, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
} }
@ -1129,9 +1130,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase) if (!bEnemyInBase)
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
} }
@ -1141,7 +1142,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
{ {
bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f)); bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f));
bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_BASE); bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_BASE) != nullptr;
if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kPhaseGateCost) + 10) { return true; } if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kPhaseGateCost) + 10) { return true; }
} }
} }
@ -1151,9 +1152,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (CappableNode) if (CappableNode)
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_RESTOWER, CappableNode->Location); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_RESTOWER, CappableNode->Location);
if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kResourceTowerCost) + 10) { return true; } if (DeployedStructure || pBot->Player->GetResources() <= BALANCE_VAR(kResourceTowerCost) + 10) { return true; }
} }
@ -1184,9 +1185,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase) if (!bEnemyInBase)
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
} }
@ -1196,7 +1197,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
{ {
bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f)); bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f));
bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_BASE); bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_BASE) != nullptr;
if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kTurretFactoryCost) + 5) { return true; } if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kTurretFactoryCost) + 5) { return true; }
@ -1217,18 +1218,18 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!vIsZero(BuildLocation)) if (!vIsZero(BuildLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), TF.Location, (BALANCE_VAR(kTurretFactoryBuildDistance) * 0.8f)); BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), TF.Location, (BALANCE_VAR(kTurretFactoryBuildDistance) * 0.8f));
if (!vIsZero(BuildLocation)) if (!vIsZero(BuildLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kSentryCost) + 5) { return true; } if (DeployedStructure || pBot->Player->GetResources() <= BALANCE_VAR(kSentryCost) + 5) { return true; }
} }
} }
@ -1259,9 +1260,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase) if (!bEnemyInBase)
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMSLAB, BuildLocation, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMSLAB, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
} }
@ -1271,7 +1272,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
{ {
bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f)); bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f));
bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMSLAB, BuildLocation, STRUCTURE_PURPOSE_BASE); bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_ARMSLAB, BuildLocation, STRUCTURE_PURPOSE_BASE) != nullptr;
if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kArmsLabCost) + 10) { return true; } if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kArmsLabCost) + 10) { return true; }
} }
@ -1293,9 +1294,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase) if (!bEnemyInBase)
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_OBSERVATORY, BuildLocation, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_OBSERVATORY, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
} }
@ -1305,7 +1306,7 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
{ {
bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f)); bool bEnemyInBase = AITAC_AnyPlayerOnTeamWithLOS(AIMGR_GetEnemyTeam(TeamNumber), BuildLocation + Vector(0.0f, 0.0f, 32.0f), UTIL_MetresToGoldSrcUnits(10.0f));
bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_OBSERVATORY, BuildLocation, STRUCTURE_PURPOSE_BASE); bool bSuccess = !bEnemyInBase && AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_OBSERVATORY, BuildLocation, STRUCTURE_PURPOSE_BASE) != nullptr;
if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kObservatoryCost) + 10) { return true; } if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kObservatoryCost) + 10) { return true; }
@ -1373,9 +1374,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase) if (!bEnemyInBase)
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PROTOTYPELAB, BuildLocation, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PROTOTYPELAB, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
} }
@ -1387,9 +1388,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase) if (!bEnemyInBase)
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PROTOTYPELAB, BuildLocation, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PROTOTYPELAB, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
} }
@ -1401,9 +1402,9 @@ bool AICOMM_CheckForNextBuildAction(AvHAIPlayer* pBot)
if (!bEnemyInBase) if (!bEnemyInBase)
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PROTOTYPELAB, BuildLocation, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PROTOTYPELAB, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess || pBot->Player->GetResources() < BALANCE_VAR(kPrototypeLabCost) + 20) { return true; } if (DeployedStructure || pBot->Player->GetResources() < BALANCE_VAR(kPrototypeLabCost) + 20) { return true; }
} }
} }
} }
@ -2099,27 +2100,27 @@ bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinit
if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) < sqrf(UTIL_MetresToGoldSrcUnits(22.0f))) if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) < sqrf(UTIL_MetresToGoldSrcUnits(22.0f)))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, NextStructure, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, NextStructure, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(5.0f)); NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(5.0f));
if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) < sqrf(UTIL_MetresToGoldSrcUnits(22.0f))) if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) < sqrf(UTIL_MetresToGoldSrcUnits(22.0f)))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, NextStructure, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, NextStructure, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(5.0f)); NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), SiegeLocation, UTIL_MetresToGoldSrcUnits(5.0f));
if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) < sqrf(UTIL_MetresToGoldSrcUnits(22.0f))) if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) < sqrf(UTIL_MetresToGoldSrcUnits(22.0f)))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, NextStructure, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, NextStructure, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
return false; return false;
@ -2145,27 +2146,27 @@ bool AICOMM_PerformNextSiegeHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefinit
if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) <= sqrf(BALANCE_VAR(kSiegeTurretRange))) if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) <= sqrf(BALANCE_VAR(kSiegeTurretRange)))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingTF.Location, UTIL_MetresToGoldSrcUnits(5.0f)); NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), ExistingTF.Location, UTIL_MetresToGoldSrcUnits(5.0f));
if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) <= sqrf(BALANCE_VAR(kSiegeTurretRange))) if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) <= sqrf(BALANCE_VAR(kSiegeTurretRange)))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), ExistingTF.Location, UTIL_MetresToGoldSrcUnits(5.0f)); NextBuildPosition = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), ExistingTF.Location, UTIL_MetresToGoldSrcUnits(5.0f));
if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) <= sqrf(BALANCE_VAR(kSiegeTurretRange))) if (!vIsZero(NextBuildPosition) && vDist2DSq(NextBuildPosition, HiveToSiege->Location) <= sqrf(BALANCE_VAR(kSiegeTurretRange)))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, NextBuildPosition, STRUCTURE_PURPOSE_SIEGE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
} }
@ -2227,27 +2228,27 @@ bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefini
if (!vIsZero(BuildLocation)) if (!vIsZero(BuildLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), OutpostLocation, UTIL_MetresToGoldSrcUnits(5.0f)); BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), OutpostLocation, UTIL_MetresToGoldSrcUnits(5.0f));
if (!vIsZero(BuildLocation)) if (!vIsZero(BuildLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), HiveToSecure->FloorLocation, UTIL_MetresToGoldSrcUnits(5.0f)); BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), HiveToSecure->FloorLocation, UTIL_MetresToGoldSrcUnits(5.0f));
if (!vIsZero(BuildLocation)) if (!vIsZero(BuildLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
return false; return false;
@ -2268,9 +2269,9 @@ bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefini
if (!vIsZero(BuildLocation)) if (!vIsZero(BuildLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
// That failed, now try expanding the radius a bit and ignoring reachability // That failed, now try expanding the radius a bit and ignoring reachability
@ -2278,9 +2279,9 @@ bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefini
if (!vIsZero(BuildLocation)) if (!vIsZero(BuildLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
// That failed too, try putting it anywhere near the hive location // That failed too, try putting it anywhere near the hive location
@ -2288,9 +2289,9 @@ bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefini
if (!vIsZero(BuildLocation)) if (!vIsZero(BuildLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
return false; return false;
@ -2308,18 +2309,18 @@ bool AICOMM_PerformNextSecureHiveAction(AvHAIPlayer* pBot, const AvHAIHiveDefini
if (!vIsZero(BuildLocation)) if (!vIsZero(BuildLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), ExistingTF.Location, (BALANCE_VAR(kCommandStationBuildDistance) * 0.8f)); BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), ExistingTF.Location, (BALANCE_VAR(kCommandStationBuildDistance) * 0.8f));
if (!vIsZero(BuildLocation)) if (!vIsZero(BuildLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_FORTIFY); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_FORTIFY);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
return false; return false;
@ -2336,9 +2337,9 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair)
if (!vIsZero(BuildLocation)) if (!vIsZero(BuildLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
DeployableSearchFilter ExistingPortalFilter; DeployableSearchFilter ExistingPortalFilter;
@ -2357,9 +2358,9 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair)
if (!vIsZero(BuildLocation)) if (!vIsZero(BuildLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
} }
@ -2391,9 +2392,9 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair)
if (!vIsZero(BuildLocation)) if (!vIsZero(BuildLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
} }
@ -2402,7 +2403,7 @@ bool AICOMM_BuildInfantryPortal(AvHAIPlayer* pBot, edict_t* CommChair)
if (vIsZero(BuildLocation)) { return false; } if (vIsZero(BuildLocation)) { return false; }
return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE); return AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_INFANTRYPORTAL, BuildLocation, STRUCTURE_PURPOSE_BASE) != nullptr;
} }
bool AICOMM_CheckForNextRecycleAction(AvHAIPlayer* pBot) bool AICOMM_CheckForNextRecycleAction(AvHAIPlayer* pBot)
@ -3239,9 +3240,9 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
} }
} }
bool bSuccess = AICOMM_DeployStructure(pBot, StructureToDeploy, ProjectedDeployLocation, STRUCTURE_PURPOSE_GENERAL); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, StructureToDeploy, ProjectedDeployLocation, STRUCTURE_PURPOSE_GENERAL, true);
if (bSuccess) if (DeployedStructure)
{ {
NextRequest->bResponded = true; NextRequest->bResponded = true;
return true; return true;
@ -3252,9 +3253,9 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
if (!vIsZero(DeployLocation)) if (!vIsZero(DeployLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, StructureToDeploy, DeployLocation, STRUCTURE_PURPOSE_GENERAL); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, StructureToDeploy, DeployLocation, STRUCTURE_PURPOSE_GENERAL);
if (bSuccess) if (DeployedStructure)
{ {
NextRequest->bResponded = true; NextRequest->bResponded = true;
return true; return true;
@ -3265,9 +3266,9 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot)
if (!vIsZero(DeployLocation)) if (!vIsZero(DeployLocation))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, StructureToDeploy, DeployLocation, STRUCTURE_PURPOSE_GENERAL); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, StructureToDeploy, DeployLocation, STRUCTURE_PURPOSE_GENERAL);
if (bSuccess) if (DeployedStructure)
{ {
NextRequest->bResponded = true; NextRequest->bResponded = true;
return true; return true;
@ -4012,9 +4013,9 @@ bool AICOMM_CheckForNextRelocationAction(AvHAIPlayer* pBot)
if (CappableNode) if (CappableNode)
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_RESTOWER, CappableNode->Location); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_RESTOWER, CappableNode->Location);
if (bSuccess || pBot->Player->GetResources() <= BALANCE_VAR(kResourceTowerCost) + 10) { return true; } if (DeployedStructure || pBot->Player->GetResources() <= BALANCE_VAR(kResourceTowerCost) + 10) { return true; }
} }
@ -4035,27 +4036,27 @@ bool AICOMM_CheckForNextRelocationAction(AvHAIPlayer* pBot)
if (!vIsZero(BuildPoint)) if (!vIsZero(BuildPoint))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_COMMCHAIR, BuildPoint, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_COMMCHAIR, BuildPoint, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
BuildPoint = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), pBot->RelocationSpot, UTIL_MetresToGoldSrcUnits(2.0f)); BuildPoint = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), pBot->RelocationSpot, UTIL_MetresToGoldSrcUnits(2.0f));
if (!vIsZero(BuildPoint)) if (!vIsZero(BuildPoint))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_COMMCHAIR, BuildPoint, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_COMMCHAIR, BuildPoint, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
BuildPoint = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), pBot->RelocationSpot, UTIL_MetresToGoldSrcUnits(10.0f)); BuildPoint = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), pBot->RelocationSpot, UTIL_MetresToGoldSrcUnits(10.0f));
if (!vIsZero(BuildPoint)) if (!vIsZero(BuildPoint))
{ {
bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_COMMCHAIR, BuildPoint, STRUCTURE_PURPOSE_BASE); AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_COMMCHAIR, BuildPoint, STRUCTURE_PURPOSE_BASE);
if (bSuccess) { return true; } if (DeployedStructure) { return true; }
} }
return false; return false;
@ -4093,3 +4094,336 @@ bool AICOMM_CheckForNextRelocationAction(AvHAIPlayer* pBot)
return false; return false;
} }
bool AICOMM_BuildOutBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut)
{
if (!pBot || !BaseToBuildOut) { return false; }
switch (BaseToBuildOut->BaseType)
{
case MARINE_BASE_SIEGE:
return AICOMM_BuildOutSiege(pBot, BaseToBuildOut);
case MARINE_BASE_OUTPOST:
return AICOMM_BuildOutOutpost(pBot, BaseToBuildOut);
case MARINE_BASE_MAINBASE:
return AICOMM_BuildOutMainBase(pBot, BaseToBuildOut);
default:
return false;
}
return false;
}
bool AICOMM_BuildOutMainBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut)
{
return false;
}
bool AICOMM_BuildOutOutpost(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut)
{
AvHAIDeployableStructureType StructureToDeploy = STRUCTURE_NONE;
AvHAIBuildableStructure PhaseGate;
AvHAIBuildableStructure Armoury;
AvHAIBuildableStructure TurretFactory;
AvHAIBuildableStructure Observatory;
int NumTurrets = 0;
int NumIncomplete = 0;
for (auto it = BaseToBuildOut->PlacedStructures.begin(); it != BaseToBuildOut->PlacedStructures.end(); it++)
{
AvHAIBuildableStructure StructureRef = AITAC_GetDeployableStructureByEntIndex(BaseToBuildOut->BaseTeam, *it);
if (!StructureRef.IsCompleted()) { NumIncomplete++; }
switch (StructureRef.StructureType)
{
case STRUCTURE_MARINE_PHASEGATE:
PhaseGate = StructureRef;
break;
case STRUCTURE_MARINE_TURRETFACTORY:
case STRUCTURE_MARINE_ADVTURRETFACTORY:
TurretFactory = StructureRef;
break;
case STRUCTURE_MARINE_ARMOURY:
case STRUCTURE_MARINE_ADVARMOURY:
Armoury = StructureRef;
break;
case STRUCTURE_MARINE_OBSERVATORY:
Observatory = StructureRef;
break;
case STRUCTURE_MARINE_TURRET:
NumTurrets++;
break;
default:
break;
}
}
if (NumIncomplete > 0)
{
int NumBuilders = AITAC_GetNumPlayersOfTeamInArea(pBot->Player->GetTeam(), BaseToBuildOut->BaseLocation, UTIL_MetresToGoldSrcUnits(10.0f), false, nullptr, AVH_USER3_COMMANDER_PLAYER);
// Don't spam too many structures
if (NumIncomplete >= NumBuilders) { return false; }
}
if (PhaseGate.IsValid() && !PhaseGate.IsCompleted()) { return false; }
if (TurretFactory.IsValid() && !TurretFactory.IsCompleted()) { return false; }
if (!PhaseGate.IsValid() && AITAC_ResearchIsComplete(pBot->Player->GetTeam(), TECH_RESEARCH_PHASETECH))
{
StructureToDeploy = STRUCTURE_MARINE_PHASEGATE;
}
else if (!TurretFactory.IsValid())
{
StructureToDeploy = STRUCTURE_MARINE_TURRETFACTORY;
}
else if (TurretFactory.IsCompleted() && NumTurrets < 5)
{
StructureToDeploy = STRUCTURE_MARINE_TURRET;
}
else if (!Armoury.IsValid())
{
StructureToDeploy = STRUCTURE_MARINE_ARMOURY;
}
else if (!Observatory.IsValid())
{
StructureToDeploy = STRUCTURE_MARINE_OBSERVATORY;
}
if (StructureToDeploy == STRUCTURE_NONE) { return false; }
if (StructureToDeploy == STRUCTURE_MARINE_TURRET)
{
int NumAttempts = 0;
while (NumAttempts < 5)
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), TurretFactory.Location, (BALANCE_VAR(kTurretFactoryBuildDistance) * 0.8f));
if (!vIsZero(BuildLocation))
{
AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (DeployedStructure)
{
BaseToBuildOut->PlacedStructures.push_back(DeployedStructure->EntIndex);
return true;
}
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), TurretFactory.Location, (BALANCE_VAR(kTurretFactoryBuildDistance) * 0.8f));
if (!vIsZero(BuildLocation))
{
AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (DeployedStructure)
{
BaseToBuildOut->PlacedStructures.push_back(DeployedStructure->EntIndex);
}
if (DeployedStructure || pBot->Player->GetResources() <= BALANCE_VAR(kSentryCost) + 5) { return true; }
}
NumAttempts++;
}
return false;
}
int NumAttempts = 0;
while (NumAttempts < 5)
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), BaseToBuildOut->BaseLocation, UTIL_MetresToGoldSrcUnits(8.0f));
if (!vIsZero(BuildLocation))
{
AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, StructureToDeploy, BuildLocation, STRUCTURE_PURPOSE_BASE);
if (DeployedStructure)
{
BaseToBuildOut->PlacedStructures.push_back(DeployedStructure->EntIndex);
return true;
}
}
NumAttempts++;
}
return false;
}
bool AICOMM_BuildOutSiege(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut)
{
AvHAIDeployableStructureType StructureToDeploy = STRUCTURE_NONE;
AvHAIBuildableStructure PhaseGate;
AvHAIBuildableStructure Armoury;
AvHAIBuildableStructure TurretFactory;
AvHAIBuildableStructure Observatory;
int NumTurrets = 0;
int NumIncomplete = 0;
for (auto it = BaseToBuildOut->PlacedStructures.begin(); it != BaseToBuildOut->PlacedStructures.end(); it++)
{
AvHAIBuildableStructure StructureRef = AITAC_GetDeployableStructureByEntIndex(BaseToBuildOut->BaseTeam, *it);
if (!StructureRef.IsCompleted())
{
NumIncomplete++;
}
switch (StructureRef.StructureType)
{
case STRUCTURE_MARINE_PHASEGATE:
PhaseGate = StructureRef;
break;
case STRUCTURE_MARINE_TURRETFACTORY:
case STRUCTURE_MARINE_ADVTURRETFACTORY:
TurretFactory = StructureRef;
break;
case STRUCTURE_MARINE_ARMOURY:
case STRUCTURE_MARINE_ADVARMOURY:
Armoury = StructureRef;
break;
case STRUCTURE_MARINE_OBSERVATORY:
Observatory = StructureRef;
break;
case STRUCTURE_MARINE_SIEGETURRET:
NumTurrets++;
break;
default:
break;
}
}
if (NumIncomplete > 0)
{
int NumBuilders = AITAC_GetNumPlayersOfTeamInArea(pBot->Player->GetTeam(), BaseToBuildOut->BaseLocation, UTIL_MetresToGoldSrcUnits(10.0f), false, nullptr, AVH_USER3_COMMANDER_PLAYER);
// Don't spam too many structures
if (NumIncomplete >= NumBuilders) { return false; }
}
// Don't place any more structures until we have the phase gate up
if (PhaseGate.IsValid() && !PhaseGate.IsCompleted()) { return false; }
if (!PhaseGate.IsValid() && AITAC_ResearchIsComplete(BaseToBuildOut->BaseTeam, TECH_RESEARCH_PHASETECH))
{
StructureToDeploy = STRUCTURE_MARINE_PHASEGATE;
}
else if (!TurretFactory.IsValid())
{
StructureToDeploy = STRUCTURE_MARINE_TURRETFACTORY;
}
else if (TurretFactory.IsCompleted() && TurretFactory.IsIdle() && TurretFactory.StructureType != STRUCTURE_MARINE_ADVTURRETFACTORY)
{
return AICOMM_UpgradeStructure(pBot, &TurretFactory);
}
else if (TurretFactory.StructureType == STRUCTURE_MARINE_ADVTURRETFACTORY && NumTurrets < 3)
{
StructureToDeploy = STRUCTURE_MARINE_SIEGETURRET;
}
else if (!Armoury.IsValid())
{
StructureToDeploy = STRUCTURE_MARINE_ARMOURY;
}
else if (!Observatory.IsValid())
{
StructureToDeploy = STRUCTURE_MARINE_OBSERVATORY;
}
if (StructureToDeploy == STRUCTURE_NONE) { return false; }
if (StructureToDeploy == STRUCTURE_MARINE_SIEGETURRET)
{
int NumAttempts = 0;
while (NumAttempts < 5)
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), TurretFactory.Location, (BALANCE_VAR(kTurretFactoryBuildDistance) * 0.4f));
if (!vIsZero(BuildLocation))
{
AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, BuildLocation, STRUCTURE_PURPOSE_SIEGE);
if (DeployedStructure)
{
BaseToBuildOut->PlacedStructures.push_back(DeployedStructure->EntIndex);
return true;
}
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), TurretFactory.Location, (BALANCE_VAR(kTurretFactoryBuildDistance) * 0.6f));
if (!vIsZero(BuildLocation))
{
AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_SIEGETURRET, BuildLocation, STRUCTURE_PURPOSE_SIEGE);
if (DeployedStructure)
{
BaseToBuildOut->PlacedStructures.push_back(DeployedStructure->EntIndex);
}
if (DeployedStructure || pBot->Player->GetResources() <= BALANCE_VAR(kSentryCost) + 5) { return true; }
}
NumAttempts++;
}
return false;
}
int NumAttempts = 0;
while (NumAttempts < 5)
{
Vector BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), BaseToBuildOut->BaseLocation, UTIL_MetresToGoldSrcUnits(3.0f));
if (!vIsZero(BuildLocation))
{
AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, StructureToDeploy, BuildLocation, STRUCTURE_PURPOSE_SIEGE);
if (DeployedStructure)
{
BaseToBuildOut->PlacedStructures.push_back(DeployedStructure->EntIndex);
return true;
}
}
BuildLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), BaseToBuildOut->BaseLocation, UTIL_MetresToGoldSrcUnits(5.0f));
if (!vIsZero(BuildLocation))
{
AvHAIBuildableStructure* DeployedStructure = AICOMM_DeployStructure(pBot, StructureToDeploy, BuildLocation, STRUCTURE_PURPOSE_SIEGE);
if (DeployedStructure)
{
BaseToBuildOut->PlacedStructures.push_back(DeployedStructure->EntIndex);
return true;
}
}
NumAttempts++;
}
return false;
}
void AICOMM_AddNewBase(AvHAIPlayer* pBot, Vector NewBaseLocation, MarineBaseType NewBaseType)
{
AvHAIMarineBase NewBase;
NewBase.BaseLocation = NewBaseLocation;
NewBase.BaseType = NewBaseType;
NewBase.BaseTeam = pBot->Player->GetTeam();
pBot->Bases.push_back(NewBase);
}

View file

@ -14,7 +14,7 @@
static const float MIN_COMMANDER_REMIND_TIME = 20.0f; // How frequently the commander can nag a player to do something, if they don't think they're doing it static const float MIN_COMMANDER_REMIND_TIME = 20.0f; // How frequently the commander can nag a player to do something, if they don't think they're doing it
bool AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureType StructureToDeploy, const Vector Location, StructurePurpose Purpose = STRUCTURE_PURPOSE_GENERAL); AvHAIBuildableStructure* AICOMM_DeployStructure(AvHAIPlayer* pBot, const AvHAIDeployableStructureType StructureToDeploy, const Vector Location, StructurePurpose Purpose = STRUCTURE_PURPOSE_GENERAL, bool bPlacedByHuman = false);
bool AICOMM_DeployItem(AvHAIPlayer* pBot, const AvHAIDeployableItemType ItemToDeploy, const Vector Location); bool AICOMM_DeployItem(AvHAIPlayer* pBot, const AvHAIDeployableItemType ItemToDeploy, const Vector Location);
bool AICOMM_UpgradeStructure(AvHAIPlayer* pBot, AvHAIBuildableStructure* StructureToUpgrade); bool AICOMM_UpgradeStructure(AvHAIPlayer* pBot, AvHAIBuildableStructure* StructureToUpgrade);
bool AICOMM_ResearchTech(AvHAIPlayer* pBot, AvHAIBuildableStructure* StructureToResearch, AvHMessageID Research); bool AICOMM_ResearchTech(AvHAIPlayer* pBot, AvHAIBuildableStructure* StructureToResearch, AvHMessageID Research);
@ -76,4 +76,11 @@ bool AICOMM_ShouldCommanderRelocate(AvHAIPlayer* pBot);
bool AICOMM_GetRelocationMessage(Vector RelocationPoint, char* MessageBuffer); bool AICOMM_GetRelocationMessage(Vector RelocationPoint, char* MessageBuffer);
void AICOMM_AddNewBase(AvHAIPlayer* pBot, Vector NewBaseLocation, MarineBaseType NewBaseType);
bool AICOMM_BuildOutBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut);
bool AICOMM_BuildOutMainBase(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut);
bool AICOMM_BuildOutOutpost(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut);
bool AICOMM_BuildOutSiege(AvHAIPlayer* pBot, AvHAIMarineBase* BaseToBuildOut);
#endif // AVH_AI_COMMANDER_H #endif // AVH_AI_COMMANDER_H

View file

@ -20,6 +20,7 @@ bot_skill BotSkillLevels[4];
std::vector<AvHMessageID> ChamberSequence; std::vector<AvHMessageID> ChamberSequence;
std::default_random_engine rng;
bool bRNGSeeded = false; bool bRNGSeeded = false;
string DefaultBotNames[MAX_PLAYERS] = { "MrRobot", string DefaultBotNames[MAX_PLAYERS] = { "MrRobot",
@ -186,7 +187,6 @@ void CONFIG_PopulateBotNames()
if (BotNames.size() > 2) if (BotNames.size() > 2)
{ {
auto rng = std::default_random_engine{};
std::shuffle(begin(BotNames), end(BotNames), rng); std::shuffle(begin(BotNames), end(BotNames), rng);
} }
@ -200,7 +200,6 @@ void CONFIG_PopulateBotNames()
if (DefaultNames.size() > 2) if (DefaultNames.size() > 2)
{ {
auto rng = std::default_random_engine{};
std::shuffle(begin(DefaultNames), end(DefaultNames), rng); std::shuffle(begin(DefaultNames), end(DefaultNames), rng);
} }
@ -274,12 +273,10 @@ void CONFIG_ParseConfigFile()
ChamberSequence.push_back(ALIEN_BUILD_MOVEMENT_CHAMBER); ChamberSequence.push_back(ALIEN_BUILD_MOVEMENT_CHAMBER);
ChamberSequence.push_back(ALIEN_BUILD_SENSORY_CHAMBER); ChamberSequence.push_back(ALIEN_BUILD_SENSORY_CHAMBER);
auto rng = std::default_random_engine{};
if (!bRNGSeeded) if (!bRNGSeeded)
{ {
srand(time(NULL)); srand(time(0));
rng.seed(time(NULL)); rng.seed(time(0));
bRNGSeeded = true; bRNGSeeded = true;
} }

View file

@ -341,6 +341,7 @@ typedef struct _AVH_AI_GUARD_INFO
typedef struct _AVH_AI_BUILDABLE_STRUCTURE typedef struct _AVH_AI_BUILDABLE_STRUCTURE
{ {
AvHBaseBuildable* EntityRef = nullptr; AvHBaseBuildable* EntityRef = nullptr;
int EntIndex = -1;
edict_t* edict = nullptr; // Reference to structure edict edict_t* edict = nullptr; // Reference to structure edict
Vector Location = g_vecZero; // origin of the structure edict Vector Location = g_vecZero; // origin of the structure edict
float healthPercent = 0.0f; // Current health of the building float healthPercent = 0.0f; // Current health of the building
@ -356,9 +357,11 @@ typedef struct _AVH_AI_BUILDABLE_STRUCTURE
Vector LastSuccessfulCommanderAngle = g_vecZero; // Tracks the last commander input angle ("click" location) used to successfully place or select building Vector LastSuccessfulCommanderAngle = g_vecZero; // Tracks the last commander input angle ("click" location) used to successfully place or select building
StructurePurpose Purpose = STRUCTURE_PURPOSE_NONE; StructurePurpose Purpose = STRUCTURE_PURPOSE_NONE;
bool bReachabilityMarkedDirty = false; // If true, reachability flags will be recalculated for this structure bool bReachabilityMarkedDirty = false; // If true, reachability flags will be recalculated for this structure
bool bPlacedByHuman = true; // This structure was placed by a human: AI commander will not recycle these unless it absolutely makes sense to
bool IsValid() { return !FNullEnt(edict) && !edict->free && !(edict->v.flags & EF_NODRAW) && edict->v.deadflag == DEAD_NO; } bool IsValid() { return !FNullEnt(edict) && !edict->free && !(edict->v.flags & EF_NODRAW) && edict->v.deadflag == DEAD_NO; }
bool IsCompleted() { return (StructureStatusFlags & STRUCTURE_STATUS_COMPLETED); } bool IsCompleted() { return (StructureStatusFlags & STRUCTURE_STATUS_COMPLETED); }
bool IsIdle() { return !(StructureStatusFlags & STRUCTURE_STATUS_RESEARCHING); }
} AvHAIBuildableStructure; } AvHAIBuildableStructure;
@ -471,6 +474,24 @@ enum NavDoorType
DOORTYPE_TRAIN // Door activated by touching a trigger_once or trigger_multiple DOORTYPE_TRAIN // Door activated by touching a trigger_once or trigger_multiple
}; };
// The type of base a marine outpost could be. Used to help the AI establish and expand outposts across the map
enum MarineBaseType
{
MARINE_BASE_MAINBASE, // The main marine base, where the CC, infantry portals and stuff like arms labs go
MARINE_BASE_OUTPOST, // A permanent outpost designed to control an area of the map, but not the main marine base
MARINE_BASE_SIEGE // A siege base designed to take down an enemy base
};
typedef struct _AI_MARINE_BASE
{
AvHTeamNumber BaseTeam = TEAM_IND;
MarineBaseType BaseType = MARINE_BASE_OUTPOST; // The purpose of the base. Determines what structures the commander will place
Vector BaseLocation = ZERO_VECTOR; // Where the base should be located. The base will be grown around this location
vector<int> PlacedStructures; // Which structures are part of this base.
bool bRecycleBase = false; // Should the commander pack up and remove this base?
bool bBaseInitialised = false; // Has the commander started building this base? Will be true once a structure has been placed
} AvHAIMarineBase;
// Bot path node. A path will be several of these strung together to lead the bot to its destination // Bot path node. A path will be several of these strung together to lead the bot to its destination
typedef struct _BOT_PATH_NODE typedef struct _BOT_PATH_NODE
{ {
@ -818,6 +839,8 @@ typedef struct AVH_AI_PLAYER
Vector RelocationSpot = ZERO_VECTOR; // If the bot is commanding and wants to relocate, then this is where they plan to go Vector RelocationSpot = ZERO_VECTOR; // If the bot is commanding and wants to relocate, then this is where they plan to go
vector<AvHAIMarineBase> Bases;
} AvHAIPlayer; } AvHAIPlayer;
typedef struct _AVH_AI_SQUAD typedef struct _AVH_AI_SQUAD

View file

@ -3490,6 +3490,7 @@ void NewMove(AvHAIPlayer* pBot)
FallMove(pBot, MoveFrom, MoveTo); FallMove(pBot, MoveFrom, MoveTo);
break; break;
case SAMPLE_POLYFLAGS_JUMP: case SAMPLE_POLYFLAGS_JUMP:
case SAMPLE_POLYFLAGS_DUCKJUMP:
JumpMove(pBot, MoveFrom, MoveTo); JumpMove(pBot, MoveFrom, MoveTo);
break; break;
case SAMPLE_POLYFLAGS_BLOCKED: case SAMPLE_POLYFLAGS_BLOCKED:

View file

@ -1887,45 +1887,21 @@ void EndBotFrame(AvHAIPlayer* pBot)
void CustomThink(AvHAIPlayer* pBot) void CustomThink(AvHAIPlayer* pBot)
{ {
if (pBot->Player->GetResources() < 80.0f) if (IsPlayerAlien(pBot->Edict)) { return; }
if (!IsPlayerCommander(pBot->Edict))
{ {
pBot->Player->GiveResources(10.0f); BotProgressTakeCommandTask(pBot);
return;
} }
pBot->CurrentTask = &pBot->PrimaryBotTask; for (auto it = pBot->Bases.begin(); it != pBot->Bases.end(); it++)
AITASK_BotUpdateAndClearTasks(pBot);
if (!PlayerHasWeapon(pBot->Player, WEAPON_MARINE_MINES))
{ {
if (pBot->CurrentTask->TaskType != TASK_GET_WEAPON) if (AITAC_CanBuildOutBase(&(*it)))
{ {
AvHAIDroppedItem Mines = AITAC_FindClosestItemToLocation(pBot->Edict->v.origin, DEPLOYABLE_ITEM_MINES, pBot->Player->GetTeam(), pBot->BotNavInfo.NavProfile.ReachabilityFlag, 0.0f, 0.0f, false); if (AICOMM_BuildOutBase(pBot, &(*it))) { return; }
if (Mines.IsValid())
{
AITASK_SetPickupTask(pBot, pBot->CurrentTask, Mines.edict, true);
} }
} }
}
else
{
if (pBot->CurrentTask->TaskType != TASK_PLACE_MINE)
{
DeployableSearchFilter TFFilter;
TFFilter.DeployableTypes = STRUCTURE_MARINE_TURRETFACTORY;
AvHAIBuildableStructure NearestTF = AITAC_FindClosestDeployableToLocation(pBot->Edict->v.origin, &TFFilter);
if (NearestTF.IsValid())
{
AITASK_SetMineStructureTask(pBot, pBot->CurrentTask, NearestTF.edict, true);
}
}
}
BotProgressTask(pBot, pBot->CurrentTask);
} }
void DroneThink(AvHAIPlayer* pBot) void DroneThink(AvHAIPlayer* pBot)

View file

@ -74,6 +74,9 @@ float LastSeenLerkTeamBTime = 0.0f;
vector<AvHAISquad> ActiveSquads; vector<AvHAISquad> ActiveSquads;
vector<AvHAIMarineBase> ActiveTeamABases; // If Team A are marines, any active bases they have established around the map
vector<AvHAIMarineBase> ActiveTeamBBases; // If Team B are marines, any active bases they have established around the map
std::vector<AvHAIBuildableStructure> AITAC_FindAllDeployables(const Vector& Location, const DeployableSearchFilter* Filter) std::vector<AvHAIBuildableStructure> AITAC_FindAllDeployables(const Vector& Location, const DeployableSearchFilter* Filter)
{ {
std::vector<AvHAIBuildableStructure> Result; std::vector<AvHAIBuildableStructure> Result;
@ -876,6 +879,16 @@ AvHAIBuildableStructure AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer*
return Result; return Result;
} }
AvHAIBuildableStructure AITAC_GetDeployableStructureByEntIndex(AvHTeamNumber Team, int EntIndex)
{
return (Team == AIMGR_GetTeamANumber()) ? TeamAStructureMap[EntIndex] : TeamBStructureMap[EntIndex];
}
AvHAIBuildableStructure* AITAC_GetDeployableStructureRefByEntIndex(AvHTeamNumber Team, int EntIndex)
{
return (Team == AIMGR_GetTeamANumber()) ? &TeamAStructureMap[EntIndex] : &TeamBStructureMap[EntIndex];
}
AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachableByRef(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter) AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachableByRef(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter)
{ {
AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber(); AvHTeamNumber TeamA = GetGameRules()->GetTeamANumber();
@ -2452,6 +2465,7 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
if (StructureRef->LastSeen == 0) if (StructureRef->LastSeen == 0)
{ {
StructureRef->Location = BuildingEdict->v.origin; StructureRef->Location = BuildingEdict->v.origin;
StructureRef->EntIndex = EntIndex;
StructureRef->edict = BuildingEdict; StructureRef->edict = BuildingEdict;
StructureRef->healthPercent = 1.0f; StructureRef->healthPercent = 1.0f;
StructureRef->EntityRef = nullptr; StructureRef->EntityRef = nullptr;
@ -2480,6 +2494,7 @@ AvHAIBuildableStructure* AITAC_UpdateBuildableStructure(CBaseEntity* Structure)
{ {
StructureRef->EntityRef = BaseBuildable; StructureRef->EntityRef = BaseBuildable;
StructureRef->edict = BuildingEdict; StructureRef->edict = BuildingEdict;
StructureRef->EntIndex = EntIndex;
StructureRef->OffMeshConnections.clear(); StructureRef->OffMeshConnections.clear();
StructureRef->Obstacles.clear(); StructureRef->Obstacles.clear();
@ -5946,3 +5961,268 @@ void AITAC_DetermineRelocationEnabled()
bEnableRelocation = (RandomRoll <= CONFIG_GetRelocationChance()); bEnableRelocation = (RandomRoll <= CONFIG_GetRelocationChance());
} }
} }
bool AITAC_IsMarineBaseValid(AvHAIMarineBase* Base)
{
if (Base->PlacedStructures.size() > 0) { return true; }
if ((Base->bRecycleBase || Base->bBaseInitialised) && Base->PlacedStructures.size() == 0) { return false; }
return true;
}
void AITAC_ManageActiveMarineBases()
{
for (auto it = ActiveTeamABases.begin(); it != ActiveTeamABases.end();)
{
for (auto structIt = it->PlacedStructures.begin(); structIt != it->PlacedStructures.end();)
{
AvHAIBuildableStructure StructureRef = TeamAStructureMap[*structIt];
if (!StructureRef.IsValid() || (StructureRef.StructureStatusFlags & STRUCTURE_STATUS_RECYCLING))
{
structIt = it->PlacedStructures.erase(structIt);
}
else
{
structIt++;
}
}
if (!AITAC_IsMarineBaseValid(&(*it)))
{
it = ActiveTeamABases.erase(it);
}
else
{
it++;
}
}
for (auto it = ActiveTeamBBases.begin(); it != ActiveTeamBBases.end();)
{
for (auto structIt = it->PlacedStructures.begin(); structIt != it->PlacedStructures.end();)
{
AvHAIBuildableStructure StructureRef = TeamBStructureMap[*structIt];
if (!StructureRef.IsValid() || (StructureRef.StructureStatusFlags & STRUCTURE_STATUS_RECYCLING))
{
structIt = it->PlacedStructures.erase(structIt);
}
else
{
structIt++;
}
}
if (!AITAC_IsMarineBaseValid(&(*it)))
{
it = ActiveTeamBBases.erase(it);
}
else
{
it++;
}
}
}
void AITAC_AddNewBase(AvHTeamNumber Team, Vector NewBaseLocation, MarineBaseType NewBaseType)
{
vector<AvHAIMarineBase>& BaseList = (Team == AIMGR_GetTeamANumber()) ? ActiveTeamABases : ActiveTeamBBases;
AvHAIMarineBase NewBase;
NewBase.BaseLocation = NewBaseLocation;
NewBase.BaseType = NewBaseType;
NewBase.BaseTeam = Team;
BaseList.push_back(NewBase);
}
bool AITAC_CanBuildOutBase(const AvHAIMarineBase* Base)
{
if (!Base) { return false; }
switch (Base->BaseType)
{
case MARINE_BASE_MAINBASE:
return AITAC_CanBuildOutMainBase(Base);
case MARINE_BASE_OUTPOST:
return AITAC_CanBuildOutOutpost(Base);
case MARINE_BASE_SIEGE:
return AITAC_CanBuildOutSiege(Base);
}
return false;
}
bool AITAC_CanBuildOutMainBase(const AvHAIMarineBase* Base)
{
bool bHasCommChair = false;
int NumInfPortals = 0;
bool bHasArmoury = false;
bool bHasAdvArmoury = false;
bool bArmouryCompleted = false;
bool bHasArmsLab = false;
bool bArmsLabCompleted = false;
bool bHasProtoLab = false;
bool bHasObs = false;
bool bHasPhase = false;
bool bHasTF = false;
int NumTurrets = 0;
std::unordered_map<int, AvHAIBuildableStructure>& BuildingMap = (Base->BaseTeam == AIMGR_GetTeamANumber()) ? TeamAStructureMap : TeamBStructureMap;
for (auto it = Base->PlacedStructures.begin(); it != Base->PlacedStructures.end(); it++)
{
AvHAIBuildableStructure StructureRef = BuildingMap[*it];
switch (StructureRef.StructureType)
{
case STRUCTURE_MARINE_COMMCHAIR:
bHasCommChair = true;
break;
case STRUCTURE_MARINE_INFANTRYPORTAL:
NumInfPortals++;
break;
case STRUCTURE_MARINE_ARMOURY:
bArmouryCompleted = (StructureRef.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED);
bHasArmoury = true;
break;
case STRUCTURE_MARINE_ADVARMOURY:
bArmouryCompleted = (StructureRef.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED);
bHasArmoury = true;
bHasAdvArmoury = true;
break;
case STRUCTURE_MARINE_ARMSLAB:
bHasArmsLab = true;
bArmsLabCompleted = (StructureRef.StructureStatusFlags & STRUCTURE_STATUS_COMPLETED);
break;
case STRUCTURE_MARINE_PROTOTYPELAB:
bHasProtoLab = true;
break;
case STRUCTURE_MARINE_OBSERVATORY:
bHasObs = true;
break;
case STRUCTURE_MARINE_PHASEGATE:
bHasPhase = true;
break;
case STRUCTURE_MARINE_TURRETFACTORY:
case STRUCTURE_MARINE_ADVTURRETFACTORY:
bHasTF = true;
break;
case STRUCTURE_MARINE_TURRET:
NumTurrets++;
break;
default:
break;
}
}
return (!bHasCommChair
|| NumInfPortals < 2
|| !bHasArmoury
|| !bHasAdvArmoury
|| (!bHasArmsLab && bArmouryCompleted)
|| (!bHasProtoLab && bHasAdvArmoury && bArmsLabCompleted)
|| (!bHasObs && bArmouryCompleted)
|| (!bHasPhase && AITAC_ResearchIsComplete(Base->BaseTeam, TECH_PHASE_GATE))
|| !bHasTF
|| NumTurrets < 5);
}
bool AITAC_CanBuildOutOutpost(const AvHAIMarineBase* Base)
{
bool bHasArmoury = false;
bool bHasObs = false;
bool bHasPhase = false;
bool bHasTF = false;
int NumTurrets = 0;
std::unordered_map<int, AvHAIBuildableStructure>& BuildingMap = (Base->BaseTeam == AIMGR_GetTeamANumber()) ? TeamAStructureMap : TeamBStructureMap;
for (auto it = Base->PlacedStructures.begin(); it != Base->PlacedStructures.end(); it++)
{
AvHAIBuildableStructure StructureRef = BuildingMap[*it];
switch (StructureRef.StructureType)
{
case STRUCTURE_MARINE_ARMOURY:
case STRUCTURE_MARINE_ADVARMOURY:
bHasArmoury = true;
break;
case STRUCTURE_MARINE_OBSERVATORY:
bHasObs = true;
break;
case STRUCTURE_MARINE_PHASEGATE:
bHasPhase = true;
break;
case STRUCTURE_MARINE_TURRETFACTORY:
case STRUCTURE_MARINE_ADVTURRETFACTORY:
bHasTF = true;
break;
case STRUCTURE_MARINE_TURRET:
NumTurrets++;
break;
default:
break;
}
}
return (!bHasArmoury
|| !bHasObs
|| (!bHasPhase && AITAC_ResearchIsComplete(Base->BaseTeam, TECH_PHASE_GATE))
|| !bHasTF
|| NumTurrets < 5);
}
bool AITAC_CanBuildOutSiege(const AvHAIMarineBase* Base)
{
bool bHasArmoury = false;
bool bHasObs = false;
bool bHasPhase = false;
bool bHasTF = false;
int NumTurrets = 0;
std::unordered_map<int, AvHAIBuildableStructure>& BuildingMap = (Base->BaseTeam == AIMGR_GetTeamANumber()) ? TeamAStructureMap : TeamBStructureMap;
for (auto it = Base->PlacedStructures.begin(); it != Base->PlacedStructures.end(); it++)
{
AvHAIBuildableStructure StructureRef = BuildingMap[*it];
switch (StructureRef.StructureType)
{
case STRUCTURE_MARINE_ARMOURY:
case STRUCTURE_MARINE_ADVARMOURY:
bHasArmoury = true;
break;
case STRUCTURE_MARINE_OBSERVATORY:
bHasObs = true;
break;
case STRUCTURE_MARINE_PHASEGATE:
bHasPhase = true;
break;
case STRUCTURE_MARINE_ADVTURRETFACTORY:
bHasTF = true;
break;
case STRUCTURE_MARINE_SIEGETURRET:
NumTurrets++;
break;
default:
break;
}
}
return (!bHasArmoury
|| !bHasObs
|| (!bHasPhase && AITAC_ResearchIsComplete(Base->BaseTeam, TECH_PHASE_GATE))
|| !bHasTF
|| NumTurrets < 3);
}
vector<AvHAIMarineBase>& AITAC_GetTeamBases(AvHTeamNumber Team)
{
return (Team == AIMGR_GetTeamANumber()) ? ActiveTeamABases : ActiveTeamBBases;
}

View file

@ -31,6 +31,8 @@ AvHAIBuildableStructure AITAC_GetDeployableFromEdict(const edict_t* Structure);
AvHAIBuildableStructure* AITAC_GetDeployableRefFromEdict(const edict_t* Structure); AvHAIBuildableStructure* AITAC_GetDeployableRefFromEdict(const edict_t* Structure);
AvHAIBuildableStructure AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter); AvHAIBuildableStructure AITAC_GetNearestDeployableDirectlyReachable(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter);
AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachableByRef(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter); AvHAIBuildableStructure* AITAC_GetNearestDeployableDirectlyReachableByRef(AvHAIPlayer* pBot, const Vector Location, const DeployableSearchFilter* Filter);
AvHAIBuildableStructure AITAC_GetDeployableStructureByEntIndex(AvHTeamNumber Team, int EntIndex);
AvHAIBuildableStructure* AITAC_GetDeployableStructureRefByEntIndex(AvHTeamNumber Team, int EntIndex);
int AITAC_GetNumDeployablesNearLocation(const Vector& Location, const DeployableSearchFilter* Filter); int AITAC_GetNumDeployablesNearLocation(const Vector& Location, const DeployableSearchFilter* Filter);
void AITAC_PopulateHiveData(); void AITAC_PopulateHiveData();
void AITAC_RefreshHiveData(); void AITAC_RefreshHiveData();
@ -220,4 +222,14 @@ bool AITAC_IsRelocationEnabled();
void AITAC_DetermineRelocationEnabled(); void AITAC_DetermineRelocationEnabled();
bool AITAC_IsMarineBaseValid(AvHAIMarineBase* Base);
void AITAC_ManageActiveMarineBases();
void AITAC_AddNewBase(AvHTeamNumber Team, Vector NewBaseLocation, MarineBaseType NewBaseType);
bool AITAC_CanBuildOutBase(const AvHAIMarineBase* Base);
bool AITAC_CanBuildOutMainBase(const AvHAIMarineBase* Base);
bool AITAC_CanBuildOutOutpost(const AvHAIMarineBase* Base);
bool AITAC_CanBuildOutSiege(const AvHAIMarineBase* Base);
vector<AvHAIMarineBase>& AITAC_GetTeamBases(AvHTeamNumber Team);
#endif #endif