Avoid consecutive attempts to build naval structures

If not enough water space can be found inside the base perimeter, stop the AI from trying to build naval production buildings permanently until it deploys another construction yard.

If enough water is available within the base perimeter, check whether any
building that provides buildable area (for adjacency) is close enough to
water, otherwise don't even start producing this naval structure.
This commit is contained in:
reaperrr
2015-07-21 07:30:14 +02:00
parent 0a5b812bb7
commit 65a6489ef1
3 changed files with 114 additions and 5 deletions

View File

@@ -28,8 +28,11 @@ namespace OpenRA.Mods.Common.AI
int waitTicks;
Actor[] playerBuildings;
bool waterAvailable;
bool checkedWater;
int failCount;
int failRetryTicks;
int cachedBases;
public BaseBuilder(HackyAI ai, string category, Player p, PowerManager pm, PlayerResources pr)
{
@@ -52,6 +55,25 @@ namespace OpenRA.Mods.Common.AI
if (--waitTicks > 0)
return;
if (!checkedWater)
{
waterAvailable = ai.EnoughWaterToBuildNaval();
checkedWater = true;
}
if (!waterAvailable)
{
var currentBases = world.ActorsWithTrait<BaseBuilding>()
.Where(a => a.Actor.Owner == player)
.Count();
if (currentBases > cachedBases)
{
cachedBases = currentBases;
checkedWater = false;
}
}
playerBuildings = world.ActorsWithTrait<Building>()
.Where(a => a.Actor.Owner == player)
.Select(a => a.Actor)
@@ -181,7 +203,7 @@ namespace OpenRA.Mods.Common.AI
}
}
// Make sure that we can can spend as fast as we are earning
// Make sure that we can spend as fast as we are earning
if (ai.Info.NewProductionCashThreshold > 0 && playerResources.Resources > ai.Info.NewProductionCashThreshold)
{
var production = GetProducibleBuilding("Production", buildableThings);
@@ -198,6 +220,24 @@ namespace OpenRA.Mods.Common.AI
}
}
// Only consider building this if there is enough water inside the base perimeter and there are close enough adjacent buildings
if (waterAvailable && ai.CloseEnoughToWater()
&& ai.Info.NewProductionCashThreshold > 0 && playerResources.Resources > ai.Info.NewProductionCashThreshold)
{
var navalproduction = GetProducibleBuilding("NavalProduction", buildableThings);
if (navalproduction != null && HasSufficientPowerForActor(navalproduction))
{
HackyAI.BotDebug("AI: {0} decided to build {1}: Priority override (navalproduction)", queue.Actor.Owner, navalproduction.Name);
return navalproduction;
}
if (power != null && navalproduction != null && !HasSufficientPowerForActor(navalproduction))
{
HackyAI.BotDebug("{0} decided to build {1}: Priority override (would be low power)", queue.Actor.Owner, power.Name);
return power;
}
}
// Create some head room for resource storage if we really need it
if (playerResources.AlertSilo)
{
@@ -232,6 +272,14 @@ namespace OpenRA.Mods.Common.AI
if (ai.Info.BuildingLimits.ContainsKey(name) && ai.Info.BuildingLimits[name] <= count)
continue;
// If we're considering to build a naval structure, check whether there is enough water inside the base perimeter
// and any structure providing buildable area close enough to that water.
// TODO: Extend this check to cover any naval structure, not just production.
if (ai.Info.BuildingCommonNames.ContainsKey("NavalProduction")
&& ai.Info.BuildingCommonNames["NavalProduction"].Contains(name)
&& (!waterAvailable || !ai.CloseEnoughToWater()))
continue;
// Will this put us into low power?
var actor = world.Map.Rules.Actors[name];
if (playerPower.ExcessPower < ai.Info.MinimumExcessPower || !HasSufficientPowerForActor(actor))

View File

@@ -92,6 +92,11 @@ namespace OpenRA.Mods.Common.AI
[Desc("Radius in cells around the center of the base to expand.")]
public readonly int MaxBaseRadius = 20;
[Desc("Radius in cells around each building with ProvideBuildableArea",
"to check for a 3x3 area of water where naval structures can be built.",
"Should match maximum adjacency of naval structures.")]
public readonly int CheckForWaterRadius = 8;
[Desc("Production queues AI uses for producing units.")]
public readonly string[] UnitQueues = { "Vehicle", "Infantry", "Plane", "Ship", "Aircraft" };
@@ -257,6 +262,58 @@ namespace OpenRA.Mods.Common.AI
resourceTypeIndices.Set(World.TileSet.GetTerrainIndex(t.TerrainType), true);
}
// TODO: Possibly give this a more generic name when terrain type is unhardcoded
public bool EnoughWaterToBuildNaval()
{
var baseBuildings = World.Actors.Where(
a => a.Owner == Player
&& a.HasTrait<BaseBuilding>()
&& !a.HasTrait<Mobile>());
foreach (var b in baseBuildings)
{
// TODO: Unhardcode terrain type
var playerWorld = Player.World;
var countWaterCells = Map.FindTilesInCircle(b.Location, Info.MaxBaseRadius)
.Where(c => playerWorld.Map.Contains(c)
&& playerWorld.Map.GetTerrainInfo(c).Type == "Water"
&& Util.AdjacentCells(playerWorld, Target.FromCell(playerWorld, c))
.All(a => playerWorld.Map.GetTerrainInfo(a).Type == "Water"))
.Count();
if (countWaterCells > 0)
return true;
}
return false;
}
// Check whether we have at least one building providing buildable area close enough to water to build naval structures
public bool CloseEnoughToWater()
{
var areaProviders = World.Actors.Where(
a => a.Owner == Player
&& a.HasTrait<GivesBuildableArea>()
&& !a.HasTrait<Mobile>());
foreach (var a in areaProviders)
{
// TODO: Unhardcode terrain type
var playerWorld = Player.World;
var adjacentWater = Map.FindTilesInCircle(a.Location, Info.CheckForWaterRadius)
.Where(c => playerWorld.Map.Contains(c)
&& playerWorld.Map.GetTerrainInfo(c).Type == "Water"
&& Util.AdjacentCells(playerWorld, Target.FromCell(playerWorld, c))
.All(b => playerWorld.Map.GetTerrainInfo(b).Type == "Water"))
.Count();
if (adjacentWater > 0)
return true;
}
return false;
}
public void QueueOrder(Order order)
{
orders.Enqueue(order);

View File

@@ -8,7 +8,8 @@ Player:
Power: powr,apwr
Barracks: barr,tent
VehiclesFactory: weap
Production: barr,tent,weap,afld,hpad,spen,syrd
Production: barr,tent,weap,afld,hpad
NavalProduction: spen,syrd
Silo: silo
UnitsCommonNames:
Mcv: mcv
@@ -118,7 +119,8 @@ Player:
Power: powr,apwr
Barracks: barr,tent
VehiclesFactory: weap
Production: barr,tent,weap,afld,hpad,spen,syrd
Production: barr,tent,weap,afld,hpad
NavalProduction: spen,syrd
Silo: silo
UnitsCommonNames:
Mcv: mcv
@@ -245,7 +247,8 @@ Player:
Power: powr,apwr
Barracks: barr,tent
VehiclesFactory: weap
Production: barr,tent,weap,afld,hpad,spen,syrd
Production: barr,tent,weap,afld,hpad
NavalProduction: spen,syrd
Silo: silo
UnitsCommonNames:
Mcv: mcv
@@ -371,7 +374,8 @@ Player:
Power: powr,apwr
Barracks: barr,tent
VehiclesFactory: weap
Production: barr,tent,weap,afld,hpad,spen,syrd
Production: barr,tent,weap,afld,hpad
NavalProduction: spen,syrd
Silo: silo
UnitsCommonNames:
Mcv: mcv