diff --git a/OpenRA.Mods.RA/Buildable.cs b/OpenRA.Mods.RA/Buildable.cs index 2692286f69..cdc01bbaea 100755 --- a/OpenRA.Mods.RA/Buildable.cs +++ b/OpenRA.Mods.RA/Buildable.cs @@ -22,6 +22,7 @@ namespace OpenRA.Mods.RA public readonly string Queue; public readonly bool Hidden = false; + public readonly int BuildLimit = 0; // todo: UI fluff; doesn't belong here public readonly int BuildPaletteOrder = 9999; diff --git a/OpenRA.Mods.RA/Player/ProductionQueue.cs b/OpenRA.Mods.RA/Player/ProductionQueue.cs index cdcf526ec8..620ff27bb3 100755 --- a/OpenRA.Mods.RA/Player/ProductionQueue.cs +++ b/OpenRA.Mods.RA/Player/ProductionQueue.cs @@ -39,7 +39,7 @@ namespace OpenRA.Mods.RA public ProductionQueueInfo Info; PowerManager PlayerPower; PlayerResources playerResources; - CountryInfo Race; + readonly CountryInfo Race; // A list of things we are currently building public List Queue = new List(); @@ -48,8 +48,8 @@ namespace OpenRA.Mods.RA [Sync] public int CurrentRemainingCost { get { return QueueLength == 0 ? 0 : Queue[0].RemainingCost; } } [Sync] public int CurrentRemainingTime { get { return QueueLength == 0 ? 0 : Queue[0].RemainingTime; } } [Sync] public int CurrentSlowdown { get { return QueueLength == 0 ? 0 : Queue[0].slowdown; } } - [Sync] public bool CurrentPaused { get { return QueueLength == 0 ? false : Queue[0].Paused; } } - [Sync] public bool CurrentDone { get { return QueueLength == 0 ? false : Queue[0].Done; } } + [Sync] public bool CurrentPaused { get { return QueueLength != 0 && Queue[0].Paused; } } + [Sync] public bool CurrentDone { get { return QueueLength != 0 && Queue[0].Done; } } // A list of things we could possibly build, even if our race doesn't normally get it public Dictionary Produceable; @@ -106,9 +106,9 @@ namespace OpenRA.Mods.RA var bi = a.Traits.Get(); // Can our race build this by satisfying normal prereqs? var buildable = bi.Owner.Contains(Race.Race); - tech.Add(a, new ProductionState() { Visible = buildable && !bi.Hidden }); + tech.Add(a, new ProductionState { Visible = buildable && !bi.Hidden }); if (buildable) - ttc.Add(a.Name, a.Traits.Get().Prerequisites.ToList(), this); + ttc.Add(a.Name, bi, this); } return tech; @@ -175,7 +175,7 @@ namespace OpenRA.Mods.RA public virtual void Tick(Actor self) { - while (Queue.Count > 0 && !BuildableItems().Any(b => b.Name == Queue[ 0 ].Item)) + while (Queue.Count > 0 && BuildableItems().All(b => b.Name != Queue[ 0 ].Item)) { playerResources.GiveCash(Queue[0].TotalCost - Queue[0].RemainingCost); // refund what's been paid so far. FinishProduction(); @@ -198,13 +198,25 @@ namespace OpenRA.Mods.RA var cost = unit.Traits.Contains() ? unit.Traits.Get().Cost : 0; var time = GetBuildTime(order.TargetString); - if (!BuildableItems().Any(b => b.Name == order.TargetString)) + if (BuildableItems().All(b => b.Name != order.TargetString)) return; /* you can't build that!! */ + // Check if the player is trying to build more units that they are allowed + if (bi.BuildLimit > 0) + { + var inQueue = Queue.Count(pi => pi.Item == order.TargetString); + var owned = self.Owner.World.ActorsWithTrait().Count(a => a.Actor.Info.Name == order.TargetString && a.Actor.Owner == self.Owner); + if (inQueue + owned >= bi.BuildLimit) + { + Sound.PlayNotification(self.Owner, "Speech", Info.BlockedAudio, self.Owner.Country.Race); + return; + } + } + for (var n = 0; n < order.TargetLocation.X; n++) // repeat count { bool hasPlayedSound = false; - BeginProduction(new ProductionItem(this, order.TargetString, (int)time, cost, PlayerPower, + BeginProduction(new ProductionItem(this, order.TargetString, time, cost, PlayerPower, () => self.World.AddFrameEndTask( _ => { diff --git a/OpenRA.Mods.RA/Player/TechTree.cs b/OpenRA.Mods.RA/Player/TechTree.cs index cfd4ba225e..7e78e0a60b 100755 --- a/OpenRA.Mods.RA/Player/TechTree.cs +++ b/OpenRA.Mods.RA/Player/TechTree.cs @@ -34,20 +34,21 @@ namespace OpenRA.Mods.RA public void ActorChanged(Actor a) { - if (a.Owner == player && a.HasTrait()) + var bi = a.Info.Traits.GetOrDefault(); + if (a.Owner == player && (a.HasTrait() || (bi != null && bi.BuildLimit > 0))) Update(); } public void Update() { - var buildings = GatherBuildings(player); + var buildables = GatherBuildables(player); foreach(var w in watchers) - w.Update(buildings); + w.Update(buildables); } - public void Add(string key, List prerequisites, ITechTreeElement tte) + public void Add(string key, BuildableInfo info, ITechTreeElement tte) { - watchers.Add(new Watcher( key, prerequisites, tte )); + watchers.Add(new Watcher( key, info, tte )); } public void Remove(string key) @@ -55,18 +56,24 @@ namespace OpenRA.Mods.RA watchers.RemoveAll(x => x.key == key); } - static Cache> GatherBuildings( Player player ) + static Cache> GatherBuildables( Player player ) { var ret = new Cache>( x => new List() ); if (player == null) return ret; - + // Add buildables that provide prerequisites foreach (var b in player.World.ActorsWithTrait() .Where(a => a.Actor.IsInWorld && !a.Actor.IsDead() && a.Actor.Owner == player)) foreach (var p in b.Trait.ProvidesPrerequisites) ret[ p ].Add( b.Actor ); + // Add buildables that have a build limit set and are not already in the list + player.World.ActorsWithTrait() + .Where(a => a.Actor.Info.Traits.Get().BuildLimit > 0 && !a.Actor.IsDead() && a.Actor.Owner == player && ret.Keys.All(k => k != a.Actor.Info.Name)) + .ToList() + .ForEach(b => ret[b.Actor.Info.Name].Add(b.Actor)); + return ret; } @@ -74,30 +81,30 @@ namespace OpenRA.Mods.RA { public readonly string key; // strings may be either actor type, or "alternate name" key - public readonly List prerequisites; + public readonly string[] prerequisites; public readonly ITechTreeElement watcher; bool hasPrerequisites; + int buildLimit; - public Watcher(string key, List prerequisites, ITechTreeElement watcher) + public Watcher(string key, BuildableInfo info, ITechTreeElement watcher) { this.key = key; - this.prerequisites = prerequisites; + this.prerequisites = info.Prerequisites; this.watcher = watcher; this.hasPrerequisites = false; + this.buildLimit = info.BuildLimit; } - bool HasPrerequisites(Cache> buildings) + bool HasPrerequisites(Cache> buildables) { - foreach (var p in prerequisites) - if (p.StartsWith("!") ^ - !buildings.Keys.Contains(p.Replace("!",""))) - return false; - return true; + return prerequisites.All(p => !(p.StartsWith("!") ^ !buildables.Keys.Contains(p.Replace("!", "")))); } - public void Update(Cache> buildings) + public void Update(Cache> buildables) { - var nowHasPrerequisites = HasPrerequisites(buildings); + var hasReachedBuildLimit = buildLimit > 0 && buildables[key].Count >= buildLimit; + + var nowHasPrerequisites = HasPrerequisites(buildables) && !hasReachedBuildLimit; if( nowHasPrerequisites && !hasPrerequisites ) watcher.PrerequisitesAvailable(key);