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:
@@ -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?
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user