diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj
index 512a8b1784..c9ff15ba07 100755
--- a/OpenRA.Game/OpenRA.Game.csproj
+++ b/OpenRA.Game/OpenRA.Game.csproj
@@ -227,6 +227,7 @@
+
diff --git a/OpenRA.Game/Player.cs b/OpenRA.Game/Player.cs
index 6205c313bd..d25c7e21be 100644
--- a/OpenRA.Game/Player.cs
+++ b/OpenRA.Game/Player.cs
@@ -46,8 +46,6 @@ namespace OpenRA
{
World = world;
Shroud = new ShroudRenderer(this, world.Map);
-
- PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
Index = index;
Palette = "player"+index;
@@ -63,15 +61,14 @@ namespace OpenRA
PlayerRef = pr;
- RegisterPlayerColor(world, Palette);
+ RegisterPlayerColor(world, Palette);
+ PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
}
public Player( World world, Session.Client client, PlayerReference pr, int index )
{
World = world;
Shroud = new ShroudRenderer(this, world.Map);
-
- PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
Index = index;
Palette = "player"+index;
@@ -86,7 +83,8 @@ namespace OpenRA
ClientIndex = client.Index;
PlayerRef = pr;
- RegisterPlayerColor(world, Palette);
+ RegisterPlayerColor(world, Palette);
+ PlayerActor = world.CreateActor("Player", new TypeDictionary{ new OwnerInit( this ) });
}
public void RegisterPlayerColor(World world, string palette)
diff --git a/OpenRA.Game/Traits/Player/PlayerProductionQueue.cs b/OpenRA.Game/Traits/Player/PlayerProductionQueue.cs
new file mode 100644
index 0000000000..5c69f12394
--- /dev/null
+++ b/OpenRA.Game/Traits/Player/PlayerProductionQueue.cs
@@ -0,0 +1,77 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
+ * This file is part of OpenRA, which is free software. It is made
+ * available to you under the terms of the GNU General Public License
+ * as published by the Free Software Foundation. For more information,
+ * see LICENSE.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using OpenRA.FileFormats;
+
+namespace OpenRA.Traits
+{
+ public class PlayerProductionQueueInfo : ProductionQueueInfo, ITraitPrerequisite
+ {
+ public override object Create(ActorInitializer init) { return new PlayerProductionQueue(init.self, this); }
+ }
+
+ public class PlayerProductionQueue : ProductionQueue
+ {
+ public PlayerProductionQueue( Actor self, PlayerProductionQueueInfo info )
+ : base(self, self, info as ProductionQueueInfo) {}
+
+ [Sync] bool QueueActive = true;
+ public override void Tick( Actor self )
+ {
+ if (self == self.Owner.PlayerActor)
+ QueueActive = self.World.Queries.OwnedBy[self.Owner].WithTrait()
+ .Where(x => x.Trait.Info.Produces.Contains(Info.Type))
+ .Any();
+
+ base.Tick(self);
+ }
+
+ ActorInfo[] None = new ActorInfo[]{};
+ public override IEnumerable AllItems()
+ {
+ return QueueActive ? base.AllItems() : None;
+ }
+
+ public override IEnumerable BuildableItems()
+ {
+ return QueueActive ? base.BuildableItems() : None;
+ }
+
+ protected override void BuildUnit( string name )
+ {
+ // original ra behavior; queue lives on PlayerActor, need to find a production structure
+ var producers = self.World.Queries.OwnedBy[self.Owner]
+ .WithTrait()
+ .Where(x => x.Trait.Info.Produces.Contains(Info.Type))
+ .OrderByDescending(x => x.Actor.IsPrimaryBuilding() ? 1 : 0 ) // prioritize the primary.
+ .ToArray();
+
+ if (producers.Length == 0)
+ {
+ CancelProduction(name);
+ return;
+ }
+
+ foreach (var p in producers)
+ {
+ if (IsDisabledBuilding(p.Actor)) continue;
+
+ if (p.Trait.Produce(p.Actor, Rules.Info[ name ]))
+ {
+ FinishProduction();
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/OpenRA.Game/Traits/Player/ProductionQueue.cs b/OpenRA.Game/Traits/Player/ProductionQueue.cs
index 44422fde9f..988d007506 100644
--- a/OpenRA.Game/Traits/Player/ProductionQueue.cs
+++ b/OpenRA.Game/Traits/Player/ProductionQueue.cs
@@ -20,7 +20,7 @@ namespace OpenRA.Traits
public readonly string Type = null;
public float BuildSpeed = 0.4f;
public readonly int LowPowerSlowdown = 3;
- public object Create(ActorInitializer init) { return new ProductionQueue(init.self, this); }
+ public virtual object Create(ActorInitializer init) { return new ProductionQueue(init.self, init.self.Owner.PlayerActor, this); }
}
public class ProductionQueue : IResolveOrder, ITick, ITechTreeElement
@@ -35,18 +35,12 @@ namespace OpenRA.Traits
// A list of things we could possibly build, even if our race doesn't normally get it
Dictionary Produceable = new Dictionary();
- public ProductionQueue( Actor self, ProductionQueueInfo info )
+ public ProductionQueue( Actor self, Actor playerActor, ProductionQueueInfo info )
{
this.self = self;
this.Info = info;
- }
-
- // Trait initialization bites us when queue lives on PlayerActor; delay init until first tick
- bool initialized = false;
- void Initialize()
- {
- initialized = true;
- var ttc = self.Owner.PlayerActor.Trait();
+
+ var ttc = playerActor.Trait();
foreach (var a in Rules.TechTree.AllBuildables(Info.Type))
{
var bi = a.Traits.Get();
@@ -88,23 +82,16 @@ namespace OpenRA.Traits
return Queue;
}
- ActorInfo[] None = new ActorInfo[]{};
- public IEnumerable AllItems()
- {
- if (!QueueActive)
- return None;
-
+ public virtual IEnumerable AllItems()
+ {
if (Game.LobbyInfo.GlobalSettings.AllowCheats && self.Owner.PlayerActor.Trait().AllTech)
return Produceable.Select(a => a.Key);
return Produceable.Where(a => a.Value.Buildable || a.Value.Visible).Select(a => a.Key);
}
- public IEnumerable BuildableItems()
+ public virtual IEnumerable BuildableItems()
{
- if (!QueueActive)
- return None;
-
if (Game.LobbyInfo.GlobalSettings.AllowCheats && self.Owner.PlayerActor.Trait().AllTech)
return Produceable.Select(a => a.Key);
@@ -117,17 +104,8 @@ namespace OpenRA.Traits
return Rules.TechTree.CanBuild(actor, self.Owner, buildings);
}
- [Sync] bool QueueActive = true;
- public void Tick( Actor self )
- {
- if (!initialized)
- Initialize();
-
- if (self == self.Owner.PlayerActor)
- QueueActive = self.World.Queries.OwnedBy[self.Owner].WithTrait()
- .Where(x => x.Trait.Info.Produces.Contains(Info.Type))
- .Any();
-
+ public virtual void Tick( Actor self )
+ {
while( Queue.Count > 0 && !BuildableItems().Any(b => b.Name == Queue[ 0 ].Item) )
{
self.Owner.PlayerActor.Trait().GiveCash(Queue[0].TotalCost - Queue[0].RemainingCost); // refund what's been paid so far.
@@ -204,7 +182,7 @@ namespace OpenRA.Traits
return (int) time;
}
- void CancelProduction( string itemName )
+ protected void CancelProduction( string itemName )
{
if (Queue.Count == 0)
return; // Nothing to do here
@@ -226,52 +204,23 @@ namespace OpenRA.Traits
Queue.RemoveAt(0);
}
- void BeginProduction( ProductionItem item )
+ protected void BeginProduction( ProductionItem item )
{
Queue.Add(item);
}
- static bool IsDisabledBuilding(Actor a)
+ protected static bool IsDisabledBuilding(Actor a)
{
var building = a.TraitOrDefault();
return building != null && building.Disabled;
}
- void BuildUnit( string name )
+ protected virtual void BuildUnit( string name )
{
- if (self == self.Owner.PlayerActor)
- {
- // original ra behavior; queue lives on PlayerActor, need to find a production structure
- var producers = self.World.Queries.OwnedBy[self.Owner]
- .WithTrait()
- .Where(x => x.Trait.Info.Produces.Contains(Info.Type))
- .OrderByDescending(x => x.Actor.IsPrimaryBuilding() ? 1 : 0 ) // prioritize the primary.
- .ToArray();
-
- if (producers.Length == 0)
- {
- CancelProduction(name);
- return;
- }
-
- foreach (var p in producers)
- {
- if (IsDisabledBuilding(p.Actor)) continue;
-
- if (p.Trait.Produce(p.Actor, Rules.Info[ name ]))
- {
- FinishProduction();
- break;
- }
- }
- }
- else
- {
- // queue lives on actor; is produced at same actor
- var sp = self.TraitsImplementing().Where(p => p.Info.Produces.Contains(Info.Type)).FirstOrDefault();
- if (sp != null && !IsDisabledBuilding(self) && sp.Produce(self, Rules.Info[ name ]))
- FinishProduction();
- }
+ // queue lives on actor; is produced at same actor
+ var sp = self.TraitsImplementing().Where(p => p.Info.Produces.Contains(Info.Type)).FirstOrDefault();
+ if (sp != null && !IsDisabledBuilding(self) && sp.Produce(self, Rules.Info[ name ]))
+ FinishProduction();
}
}
diff --git a/OpenRA.Game/Traits/Player/TechTreeCache.cs b/OpenRA.Game/Traits/Player/TechTreeCache.cs
index b5f8a089ff..30575f579a 100755
--- a/OpenRA.Game/Traits/Player/TechTreeCache.cs
+++ b/OpenRA.Game/Traits/Player/TechTreeCache.cs
@@ -15,10 +15,45 @@ using OpenRA.GameRules;
namespace OpenRA.Traits
{
- class TechTreeCacheInfo : TraitInfo { }
-
- class TechTreeCache : ITick
+ class TechTreeCacheInfo : ITraitInfo
{
+ public object Create(ActorInitializer init) { return new TechTreeCache(init);}
+ }
+
+ class TechTreeCache
+ {
+ readonly List watchers = new List();
+ readonly Player player;
+ public TechTreeCache(ActorInitializer init)
+ {
+ player = init.self.Owner;
+ init.world.ActorAdded += ActorChanged;
+ init.world.ActorRemoved += ActorChanged;
+ }
+
+ public void ActorChanged(Actor a)
+ {
+ if (a.Owner == player && a.HasTrait())
+ Update();
+ }
+
+ public void Update()
+ {
+ var buildings = Rules.TechTree.GatherBuildings(player);
+ foreach(var w in watchers)
+ w.Update(buildings);
+ }
+
+ public void Add(string key, List prerequisites, ITechTreeElement tte)
+ {
+ watchers.Add(new Watcher( key, prerequisites, tte ));
+ }
+
+ public void Remove(string key)
+ {
+ watchers.RemoveAll(x => x.key == key);
+ }
+
class Watcher
{
public readonly string key;
@@ -35,10 +70,16 @@ namespace OpenRA.Traits
this.hasPrerequisites = false;
}
- public void Tick( Player owner, Cache> buildings )
+ public void Update(Cache> buildings)
{
- var nowHasPrerequisites = prerequisites.All( a => buildings[ a ].Any( b => !b.Trait().Disabled ) );
-
+ var nowHasPrerequisites = true;
+ foreach (var p in prerequisites)
+ if (!buildings.Keys.Contains(p))
+ {
+ nowHasPrerequisites = false;
+ break;
+ }
+
if( nowHasPrerequisites && !hasPrerequisites )
watcher.PrerequisitesAvailable(key);
@@ -48,26 +89,6 @@ namespace OpenRA.Traits
hasPrerequisites = nowHasPrerequisites;
}
}
-
- readonly List watchers = new List();
-
- public void Tick( Actor self )
- {
- var buildings = Rules.TechTree.GatherBuildings( self.Owner );
-
- foreach( var w in watchers )
- w.Tick( self.Owner, buildings );
- }
-
- public void Add( string key, List prerequisites, ITechTreeElement tte )
- {
- watchers.Add( new Watcher( key, prerequisites, tte ) );
- }
-
- public void Remove( string key )
- {
- watchers.RemoveAll( x => x.key == key );
- }
}
interface ITechTreeElement
diff --git a/mods/ra/rules/system.yaml b/mods/ra/rules/system.yaml
index 9f4ca1de39..751ca48bae 100644
--- a/mods/ra/rules/system.yaml
+++ b/mods/ra/rules/system.yaml
@@ -1,26 +1,26 @@
Player:
TechTreeCache:
- ProductionQueue@Building:
+ PlayerProductionQueue@Building:
Type: Building
BuildSpeed: .4
LowPowerSlowdown: 3
- ProductionQueue@Defense:
+ PlayerProductionQueue@Defense:
Type: Defense
BuildSpeed: .4
LowPowerSlowdown: 3
- ProductionQueue@Vehicle:
+ PlayerProductionQueue@Vehicle:
Type: Vehicle
BuildSpeed: .4
LowPowerSlowdown: 3
- ProductionQueue@Infantry:
+ PlayerProductionQueue@Infantry:
Type: Infantry
BuildSpeed: .4
LowPowerSlowdown: 3
- ProductionQueue@Ship:
+ PlayerProductionQueue@Ship:
Type: Ship
BuildSpeed: .4
LowPowerSlowdown: 3
- ProductionQueue@Plane:
+ PlayerProductionQueue@Plane:
Type: Plane
BuildSpeed: .4
LowPowerSlowdown: 3