diff --git a/OpenRA.Mods.Common/AI/BaseBuilder.cs b/OpenRA.Mods.Common/AI/BaseBuilder.cs index 97edb93780..8862c59de3 100644 --- a/OpenRA.Mods.Common/AI/BaseBuilder.cs +++ b/OpenRA.Mods.Common/AI/BaseBuilder.cs @@ -28,6 +28,8 @@ namespace OpenRA.Mods.Common.AI int waitTicks; Actor[] playerBuildings; + int failCount; + int failRetryTicks; public BaseBuilder(HackyAI ai, string category, Player p, PowerManager pm, PlayerResources pr) { @@ -37,10 +39,15 @@ namespace OpenRA.Mods.Common.AI playerPower = pm; playerResources = pr; this.category = category; + failRetryTicks = ai.Info.StructureProductionResumeDelay; } public void Tick() { + // If failed to place something N consecutive times, wait M ticks until resuming building production + if (failCount >= ai.Info.MaximumFailedPlacementAttempts && --failRetryTicks <= 0) + failCount = 0; + // Only update once per second or so if (--waitTicks > 0) return; @@ -63,7 +70,7 @@ namespace OpenRA.Mods.Common.AI var currentBuilding = queue.CurrentItem(); // Waiting to build something - if (currentBuilding == null) + if (currentBuilding == null && failCount < ai.Info.MaximumFailedPlacementAttempts) { var item = ChooseBuildingToBuild(queue); if (item == null) @@ -77,6 +84,7 @@ namespace OpenRA.Mods.Common.AI // Production is complete // Choose the placement logic // HACK: HACK HACK HACK + // TODO: Derive this from BuildingCommonNames instead var type = BuildingType.Building; if (world.Map.Rules.Actors[currentBuilding.Item].Traits.Contains()) type = BuildingType.Defense; @@ -88,9 +96,11 @@ namespace OpenRA.Mods.Common.AI { HackyAI.BotDebug("AI: {0} has nowhere to place {1}".F(player, currentBuilding.Item)); ai.QueueOrder(Order.CancelProduction(queue.Actor, currentBuilding.Item, 1)); + failCount += failCount; } else { + failCount = 0; ai.QueueOrder(new Order("PlaceBuilding", player.PlayerActor, false) { TargetLocation = location.Value, diff --git a/OpenRA.Mods.Common/AI/HackyAI.cs b/OpenRA.Mods.Common/AI/HackyAI.cs index 82485786bc..15225e8a1c 100644 --- a/OpenRA.Mods.Common/AI/HackyAI.cs +++ b/OpenRA.Mods.Common/AI/HackyAI.cs @@ -49,6 +49,9 @@ namespace OpenRA.Mods.Common.AI [Desc("Minimum delay (in ticks) between creating squads.")] public readonly int MinimumAttackForceDelay = 0; + [Desc("Minimum portion of pending orders to issue each tick (e.g. 5 issues at least 1/5th of all pending orders). Excess orders remain queued for subsequent ticks.")] + public readonly int MinOrderQuotientPerTick = 5; + [Desc("Minimum excess power the AI should try to maintain.")] public readonly int MinimumExcessPower = 0; @@ -58,8 +61,12 @@ namespace OpenRA.Mods.Common.AI [Desc("How long to wait (in ticks) between structure production checks ticks when actively building things.")] public readonly int StructureProductionActiveDelay = 10; - [Desc("Minimum portion of pending orders to issue each tick (e.g. 5 issues at least 1/5th of all pending orders). Excess orders remain queued for subsequent ticks.")] - public readonly int MinOrderQuotientPerTick = 5; + [Desc("How long to wait (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("Minimum range at which to build defensive structures near a combat hotspot.")] public readonly int MinimumDefenseRadius = 5;