diff --git a/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs b/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs index 1a5c980027..9efcf14f22 100644 --- a/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs +++ b/OpenRA.Mods.Common/Traits/Player/ProductionQueue.cs @@ -54,11 +54,16 @@ namespace OpenRA.Mods.Common.Traits "The filename of the audio is defined per faction in notifications.yaml.")] public readonly string ReadyAudio = "UnitReady"; - [Desc("Notification played when you can't train another unit", + [Desc("Notification played when you can't train another actor", "when the build limit exceeded or the exit is jammed.", "The filename of the audio is defined per faction in notifications.yaml.")] public readonly string BlockedAudio = "NoBuild"; + [Desc("Notification played when you can't queue another actor", + "when the queue length limit is exceeded.", + "The filename of the audio is defined per faction in notifications.yaml.")] + public readonly string LimitedAudio = null; + [Desc("Notification played when user clicks on the build palette icon.", "The filename of the audio is defined per faction in notifications.yaml.")] public readonly string QueuedAudio = "Training"; @@ -291,6 +296,42 @@ namespace OpenRA.Mods.Common.Traits queue[0].Tick(playerResources); } + public bool CanQueue(ActorInfo actor, out string notificationAudio) + { + notificationAudio = Info.BlockedAudio; + + var bi = actor.TraitInfoOrDefault(); + if (bi == null) + return false; + + if (!developerMode.AllTech) + { + if (Info.QueueLimit > 0 && queue.Count >= Info.QueueLimit) + { + notificationAudio = Info.LimitedAudio; + return false; + } + + var queueCount = queue.Count(i => i.Item == actor.Name); + if (Info.ItemLimit > 0 && queueCount >= Info.ItemLimit) + { + notificationAudio = Info.LimitedAudio; + return false; + } + + if (bi.BuildLimit > 0) + { + var owned = self.Owner.World.ActorsHavingTrait() + .Count(a => a.Info.Name == actor.Name && a.Owner == self.Owner); + if (queueCount + owned >= bi.BuildLimit) + return false; + } + } + + notificationAudio = Info.QueuedAudio; + return true; + } + public void ResolveOrder(Actor self, Order order) { if (!Enabled) diff --git a/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs b/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs index fee056c682..8662d75db8 100644 --- a/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ProductionPaletteWidget.cs @@ -275,13 +275,21 @@ namespace OpenRA.Mods.Common.Widgets return true; } - if (CurrentQueue.BuildableItems().Any(a => a.Name == icon.Name)) + var buildable = CurrentQueue.BuildableItems().FirstOrDefault(a => a.Name == icon.Name); + + if (buildable != null) { // Queue a new item Game.Sound.Play(SoundType.UI, TabClick); - Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Speech", CurrentQueue.Info.QueuedAudio, World.LocalPlayer.Faction.InternalName); - World.IssueOrder(Order.StartProduction(CurrentQueue.Actor, icon.Name, handleCount)); - return true; + string notification; + var canQueue = CurrentQueue.CanQueue(buildable, out notification); + Game.Sound.PlayNotification(World.Map.Rules, World.LocalPlayer, "Speech", notification, World.LocalPlayer.Faction.InternalName); + + if (canQueue) + { + World.IssueOrder(Order.StartProduction(CurrentQueue.Actor, icon.Name, handleCount)); + return true; + } } return false;