Improved naval placement check

Moved water checks before --waitTicks.
Use Water enum instead of multiple booleans.
Check for BaseProvider rather than BaseBuilding.
Move expensive ClosEnoughToWater check to last position for naval
production override.
This commit is contained in:
reaperrr
2015-07-26 13:45:20 +02:00
parent 76f2145db2
commit 91178d6f62
2 changed files with 47 additions and 28 deletions

View File

@@ -28,13 +28,21 @@ namespace OpenRA.Mods.Common.AI
int waitTicks;
Actor[] playerBuildings;
bool waterAvailable;
bool checkedWater;
int failCount;
int failRetryTicks;
int checkForBasesTicks;
int cachedBases;
int cachedBuildings;
enum Water
{
NotChecked,
EnoughWater,
NotEnoughWater
}
Water waterState = Water.NotChecked;
public BaseBuilder(HackyAI ai, string category, Player p, PowerManager pm, PlayerResources pr)
{
this.ai = ai;
@@ -55,7 +63,7 @@ namespace OpenRA.Mods.Common.AI
.Where(a => a.Actor.Owner == player)
.Count();
var baseProviders = world.ActorsWithTrait<BaseBuilding>()
var baseProviders = world.ActorsWithTrait<BaseProvider>()
.Where(a => a.Actor.Owner == player)
.Count();
@@ -68,29 +76,34 @@ namespace OpenRA.Mods.Common.AI
failRetryTicks = ai.Info.StructureProductionResumeDelay;
}
// Only update once per second or so
if (--waitTicks > 0)
return;
if (!checkedWater)
if (waterState == Water.NotChecked)
{
waterAvailable = ai.EnoughWaterToBuildNaval();
checkedWater = true;
if (ai.EnoughWaterToBuildNaval())
waterState = Water.EnoughWater;
else
{
waterState = Water.NotEnoughWater;
checkForBasesTicks = ai.Info.CheckForNewBasesDelay;
}
}
if (!waterAvailable)
if (waterState == Water.NotEnoughWater && --checkForBasesTicks <= 0)
{
var currentBases = world.ActorsWithTrait<BaseBuilding>()
var currentBases = world.ActorsWithTrait<BaseProvider>()
.Where(a => a.Actor.Owner == player)
.Count();
if (currentBases > cachedBases)
{
cachedBases = currentBases;
checkedWater = false;
waterState = Water.NotChecked;
}
}
// Only update once per second or so
if (--waitTicks > 0)
return;
playerBuildings = world.ActorsWithTrait<Building>()
.Where(a => a.Actor.Owner == player)
.Select(a => a.Actor)
@@ -148,7 +161,7 @@ namespace OpenRA.Mods.Common.AI
.Where(a => a.Actor.Owner == player)
.Count();
cachedBases = world.ActorsWithTrait<BaseBuilding>()
cachedBases = world.ActorsWithTrait<BaseProvider>()
.Where(a => a.Actor.Owner == player)
.Count();
}
@@ -254,8 +267,9 @@ 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)
if (waterState == Water.EnoughWater && ai.Info.NewProductionCashThreshold > 0
&& playerResources.Resources > ai.Info.NewProductionCashThreshold
&& ai.CloseEnoughToWater())
{
var navalproduction = GetProducibleBuilding("NavalProduction", buildableThings);
if (navalproduction != null && HasSufficientPowerForActor(navalproduction))
@@ -310,7 +324,7 @@ namespace OpenRA.Mods.Common.AI
// 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()))
&& (waterState == Water.NotEnoughWater || !ai.CloseEnoughToWater()))
continue;
// Will this put us into low power?

View File

@@ -55,22 +55,27 @@ namespace OpenRA.Mods.Common.AI
[Desc("Minimum excess power the AI should try to maintain.")]
public readonly int MinimumExcessPower = 0;
[Desc("Minimum delay (in ticks) between structure production checks when there is no active production.")]
[Desc("Delay (in ticks) between structure production checks when there is no active production.",
"A StructureProductionRandomBonusDelay is added to this.")]
public readonly int StructureProductionInactiveDelay = 125;
[Desc("Minimum delay (in ticks) between structure production checks when actively building things.")]
[Desc("Delay (in ticks) between structure production checks when actively building things.",
"A StructureProductionRandomBonusDelay is added to this.")]
public readonly int StructureProductionActiveDelay = 10;
[Desc("A random delay (in ticks) of up to this is added to production delays.")]
[Desc("A random delay (in ticks) of up to this is added to active/inactive production delays.")]
public readonly int StructureProductionRandomBonusDelay = 10;
[Desc("How long to wait (in ticks) until retrying to build structure after the last 3 consecutive attempts failed.")]
[Desc("Delay (in ticks) until retrying to build structure after the last 3 consecutive attempts failed.")]
public readonly int StructureProductionResumeDelay = 1500;
[Desc("After how many failed attempts to place a structure should AI give up and wait",
"for StructureProductionResumeDelay before retrying.")]
public readonly int MaximumFailedPlacementAttempts = 3;
[Desc("Delay (in ticks) until rechecking for new BaseProviders.")]
public readonly int CheckForNewBasesDelay = 1500;
[Desc("Minimum range at which to build defensive structures near a combat hotspot.")]
public readonly int MinimumDefenseRadius = 5;
@@ -268,20 +273,20 @@ namespace OpenRA.Mods.Common.AI
// TODO: Possibly give this a more generic name when terrain type is unhardcoded
public bool EnoughWaterToBuildNaval()
{
var baseBuildings = World.Actors.Where(
var baseProviders = World.Actors.Where(
a => a.Owner == Player
&& a.HasTrait<BaseBuilding>()
&& a.HasTrait<BaseProvider>()
&& !a.HasTrait<Mobile>());
foreach (var b in baseBuildings)
foreach (var b in baseProviders)
{
// 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"
&& playerWorld.Map.GetTerrainInfo(c).IsWater
&& Util.AdjacentCells(playerWorld, Target.FromCell(playerWorld, c))
.All(a => playerWorld.Map.GetTerrainInfo(a).Type == "Water"))
.All(a => playerWorld.Map.GetTerrainInfo(a).IsWater))
.Count();
if (countWaterCells > 0)
@@ -305,9 +310,9 @@ namespace OpenRA.Mods.Common.AI
var playerWorld = Player.World;
var adjacentWater = Map.FindTilesInCircle(a.Location, Info.CheckForWaterRadius)
.Where(c => playerWorld.Map.Contains(c)
&& playerWorld.Map.GetTerrainInfo(c).Type == "Water"
&& playerWorld.Map.GetTerrainInfo(c).IsWater
&& Util.AdjacentCells(playerWorld, Target.FromCell(playerWorld, c))
.All(b => playerWorld.Map.GetTerrainInfo(b).Type == "Water"))
.All(b => playerWorld.Map.GetTerrainInfo(b).IsWater))
.Count();
if (adjacentWater > 0)