diff --git a/OpenRA.Mods.Cnc/ProductionQueueFromSelection.cs b/OpenRA.Mods.Cnc/ProductionQueueFromSelection.cs index 0ecd483def..345092e233 100644 --- a/OpenRA.Mods.Cnc/ProductionQueueFromSelection.cs +++ b/OpenRA.Mods.Cnc/ProductionQueueFromSelection.cs @@ -41,10 +41,10 @@ namespace OpenRA.Mods.Cnc.Widgets // Find an actor with a queue var producer = world.Selection.Actors.FirstOrDefault(a => a.IsInWorld && a.World.LocalPlayer == a.Owner - && a.HasTrait()); + && a.TraitsImplementing().Any(q => q.Enabled)); if (producer != null) - tabsWidget.Value.CurrentQueue = producer.TraitsImplementing().First(); + tabsWidget.Value.CurrentQueue = producer.TraitsImplementing().First(q => q.Enabled); } } } diff --git a/OpenRA.Mods.Cnc/Widgets/ProductionTabsWidget.cs b/OpenRA.Mods.Cnc/Widgets/ProductionTabsWidget.cs index 133db405ba..a7c7a19fd1 100644 --- a/OpenRA.Mods.Cnc/Widgets/ProductionTabsWidget.cs +++ b/OpenRA.Mods.Cnc/Widgets/ProductionTabsWidget.cs @@ -196,7 +196,7 @@ namespace OpenRA.Mods.Cnc.Widgets if (a.HasTrait()) { var allQueues = a.World.ActorsWithTrait() - .Where(p => p.Actor.Owner == p.Actor.World.LocalPlayer && p.Actor.IsInWorld) + .Where(p => p.Actor.Owner == p.Actor.World.LocalPlayer && p.Actor.IsInWorld && p.Trait.Enabled) .Select(p => p.Trait).ToArray(); foreach (var g in Groups.Values) diff --git a/OpenRA.Mods.D2k/Render/WithProductionOverlay.cs b/OpenRA.Mods.D2k/Render/WithProductionOverlay.cs index 65e943b97c..e27bd7233e 100644 --- a/OpenRA.Mods.D2k/Render/WithProductionOverlay.cs +++ b/OpenRA.Mods.D2k/Render/WithProductionOverlay.cs @@ -68,12 +68,12 @@ namespace OpenRA.Mods.RA.Render var production = self.TraitOrDefault(); var perBuildingQueues = self.TraitsImplementing(); - queue = perBuildingQueues.FirstOrDefault(q => production.Info.Produces.Contains(q.Info.Type)); + queue = perBuildingQueues.FirstOrDefault(q => q.Enabled && production.Info.Produces.Contains(q.Info.Type)); if (queue == null) { var perPlayerQueues = self.Owner.PlayerActor.TraitsImplementing(); - queue = perPlayerQueues.FirstOrDefault(q => production.Info.Produces.Contains(q.Info.Type)); + queue = perPlayerQueues.FirstOrDefault(q => q.Enabled && production.Info.Produces.Contains(q.Info.Type)); } if (queue == null) diff --git a/OpenRA.Mods.RA/AI/HackyAI.cs b/OpenRA.Mods.RA/AI/HackyAI.cs index 4ec02f49df..e422a63567 100644 --- a/OpenRA.Mods.RA/AI/HackyAI.cs +++ b/OpenRA.Mods.RA/AI/HackyAI.cs @@ -809,7 +809,7 @@ namespace OpenRA.Mods.RA.AI internal IEnumerable FindQueues(string category) { return world.ActorsWithTrait() - .Where(a => a.Actor.Owner == p && a.Trait.Info.Type == category) + .Where(a => a.Actor.Owner == p && a.Trait.Info.Type == category && a.Trait.Enabled) .Select(a => a.Trait); } diff --git a/OpenRA.Mods.RA/Player/ProductionQueue.cs b/OpenRA.Mods.RA/Player/ProductionQueue.cs index f6284fd517..fa253984de 100644 --- a/OpenRA.Mods.RA/Player/ProductionQueue.cs +++ b/OpenRA.Mods.RA/Player/ProductionQueue.cs @@ -30,6 +30,12 @@ namespace OpenRA.Mods.RA [Desc("Filter buildable items based on their Owner.")] public readonly bool RequireOwner = true; + [Desc("Only enable this queue for certain factions")] + public readonly string[] Race = { }; + + [Desc("Should the prerequisite remain enabled if the owner changes?")] + public readonly bool Sticky = true; + [Desc("This value is used to translate the unit cost into build time.")] public readonly float BuildSpeed = 0.4f; @@ -64,11 +70,11 @@ namespace OpenRA.Mods.RA { public readonly ProductionQueueInfo Info; readonly Actor self; - readonly string race; - // Can change if the actor is captured + // Will change if the owner changes PowerManager playerPower; PlayerResources playerResources; + string race; // A list of things we could possibly build Dictionary produceable; @@ -83,6 +89,7 @@ namespace OpenRA.Mods.RA [Sync] public int CurrentSlowdown { get { return QueueLength == 0 ? 0 : queue[0].Slowdown; } } [Sync] public bool CurrentPaused { get { return QueueLength != 0 && queue[0].Paused; } } [Sync] public bool CurrentDone { get { return QueueLength != 0 && queue[0].Done; } } + [Sync] public bool Enabled { get; private set; } public ProductionQueue(ActorInitializer init, Actor playerActor, ProductionQueueInfo info) { @@ -91,7 +98,9 @@ namespace OpenRA.Mods.RA playerResources = playerActor.Trait(); playerPower = playerActor.Trait(); - race = self.Owner.Country.Race; + race = init.Contains() ? init.Get() : self.Owner.Country.Race; + Enabled = !info.Race.Any() || info.Race.Contains(race); + CacheProduceables(playerActor); } @@ -111,6 +120,12 @@ namespace OpenRA.Mods.RA playerResources = newOwner.PlayerActor.Trait(); ClearQueue(); + if (!Info.Sticky) + { + race = self.Owner.Country.Race; + Enabled = !Info.Race.Any() || Info.Race.Contains(race); + } + // Regenerate the produceables and tech tree state oldOwner.PlayerActor.Trait().Remove(this); CacheProduceables(newOwner.PlayerActor); @@ -125,6 +140,9 @@ namespace OpenRA.Mods.RA void CacheProduceables(Actor playerActor) { produceable = new Dictionary(); + if (!Enabled) + return; + var ttc = playerActor.Trait(); foreach (var a in AllBuildables(Info.Type)) @@ -216,6 +234,9 @@ namespace OpenRA.Mods.RA public void ResolveOrder(Actor self, Order order) { + if (!Enabled) + return; + switch (order.OrderString) { case "StartProduction": diff --git a/OpenRA.Mods.RA/ProductionBar.cs b/OpenRA.Mods.RA/ProductionBar.cs index d599b1a176..557b0a28f8 100644 --- a/OpenRA.Mods.RA/ProductionBar.cs +++ b/OpenRA.Mods.RA/ProductionBar.cs @@ -44,6 +44,7 @@ namespace OpenRA.Mods.RA var type = info.ProductionType ?? self.Trait().Info.Produces.First(); // Per-actor queue + // Note: this includes disabled queues, as each bar must bind to exactly one queue. queue = self.TraitsImplementing() .FirstOrDefault(q => type == null || type == q.Info.Type); diff --git a/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs b/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs index 5a03d70456..59342d0ed7 100644 --- a/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs +++ b/OpenRA.Mods.RA/Scripting/LuaScriptInterface.cs @@ -414,7 +414,8 @@ namespace OpenRA.Mods.RA.Scripting if (bi == null) return; - var queue = factory.TraitOrDefault(); + var queue = factory.TraitsImplementing() + .FirstOrDefault(q => q.Enabled); if (queue != null) queue.ResolveOrder(factory, Order.StartProduction(factory, unit, (int)amount)); @@ -434,7 +435,8 @@ namespace OpenRA.Mods.RA.Scripting [LuaGlobal] public bool PerFactoryQueueIsBusy(Actor factory) { - var queue = factory.TraitOrDefault(); + var queue = factory.TraitsImplementing() + .FirstOrDefault(q => q.Enabled); if (queue == null) return true; diff --git a/OpenRA.Mods.RA/World/ChooseBuildTabOnSelect.cs b/OpenRA.Mods.RA/World/ChooseBuildTabOnSelect.cs index f9aaf00ffb..8c95e2e5e6 100644 --- a/OpenRA.Mods.RA/World/ChooseBuildTabOnSelect.cs +++ b/OpenRA.Mods.RA/World/ChooseBuildTabOnSelect.cs @@ -36,12 +36,12 @@ namespace OpenRA.Mods.RA return; // Queue-per-structure - var perqueue = world.Selection.Actors.FirstOrDefault( - a => a.IsInWorld && a.World.LocalPlayer == a.Owner && a.HasTrait()); + var perqueue = world.Selection.Actors.FirstOrDefault(a => a.IsInWorld && a.World.LocalPlayer == a.Owner + && a.TraitsImplementing().Any(q => q.Enabled)); if (perqueue != null) { - palette.SetCurrentTab(perqueue.TraitsImplementing().First()); + palette.SetCurrentTab(perqueue.TraitsImplementing().First(q => q.Enabled)); return; } @@ -55,7 +55,7 @@ namespace OpenRA.Mods.RA return; palette.SetCurrentTab(world.LocalPlayer.PlayerActor.TraitsImplementing() - .FirstOrDefault(t => types.Contains(t.Info.Type))); + .FirstOrDefault(q => q.Enabled && types.Contains(q.Info.Type))); } } }