diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj
index 6b97904528..307397f5a3 100755
--- a/OpenRA.Game/OpenRA.Game.csproj
+++ b/OpenRA.Game/OpenRA.Game.csproj
@@ -205,6 +205,7 @@
+
diff --git a/OpenRA.Game/Traits/Selectable.cs b/OpenRA.Game/Traits/Selectable.cs
index cb8cd7a071..5d6aefc53c 100644
--- a/OpenRA.Game/Traits/Selectable.cs
+++ b/OpenRA.Game/Traits/Selectable.cs
@@ -23,10 +23,6 @@ namespace OpenRA.Traits
public class Selectable : IPostRenderSelection
{
- // depends on the order of pips in TraitsInterfaces.cs!
- static readonly string[] pipStrings = { "pip-empty", "pip-green", "pip-yellow", "pip-red", "pip-gray", "pip-blue" };
- static readonly string[] tagStrings = { "", "tag-fake", "tag-primary" };
-
public void RenderAfterWorld (WorldRenderer wr, Actor self)
{
var bounds = self.Bounds.Value;
@@ -37,11 +33,8 @@ namespace OpenRA.Traits
wr.DrawSelectionBox(self, Color.White);
DrawHealthBar(self, xy, Xy);
- DrawControlGroup(wr, self, xy);
- DrawPips(wr, self, xY);
- DrawTags(wr, self, new float2(.5f * (bounds.Left + bounds.Right), bounds.Top));
- DrawUnitPath(self);
DrawExtraBars(self, xy, Xy);
+ DrawUnitPath(self);
}
public void DrawRollover(WorldRenderer wr, Actor self)
@@ -138,83 +131,6 @@ namespace OpenRA.Traits
}
}
- void DrawControlGroup(WorldRenderer wr, Actor self, float2 basePosition)
- {
- var group = self.World.Selection.GetControlGroupForActor(self);
- if (group == null) return;
-
- var pipImages = new Animation("pips");
- pipImages.PlayFetchIndex("groups", () => (int)group);
- pipImages.Tick();
- pipImages.Image.DrawAt(wr, basePosition + new float2(-8, 1), "chrome");
- }
-
- void DrawPips(WorldRenderer wr, Actor self, float2 basePosition)
- {
- if (self.Owner != self.World.LocalPlayer) return;
-
- var pipSources = self.TraitsImplementing();
- if (pipSources.Count() == 0)
- return;
-
- var pipImages = new Animation("pips");
- pipImages.PlayRepeating(pipStrings[0]);
-
- var pipSize = pipImages.Image.size;
- var pipxyBase = basePosition + new float2(1, -pipSize.Y);
- var pipxyOffset = new float2(0, 0); // Correct for offset due to multiple columns/rows
-
- foreach (var pips in pipSources)
- {
- var thisRow = pips.GetPips(self);
- if (thisRow == null)
- continue;
-
- var width = self.Bounds.Value.Width;
-
- foreach (var pip in thisRow)
- {
- if (pipxyOffset.X + pipSize.X >= width)
- {
- pipxyOffset.X = 0;
- pipxyOffset.Y -= pipSize.Y;
- }
- pipImages.PlayRepeating(pipStrings[(int)pip]);
- pipImages.Image.DrawAt(wr, pipxyBase + pipxyOffset, "chrome");
- pipxyOffset += new float2(pipSize.X, 0);
- }
-
- // Increment row
- pipxyOffset.X = 0;
- pipxyOffset.Y -= pipSize.Y + 1;
- }
- }
-
- void DrawTags(WorldRenderer wr, Actor self, float2 basePosition)
- {
- if (self.Owner != self.World.LocalPlayer) return;
-
- // If a mod wants to implement a unit with multiple tags, then they are placed on multiple rows
- var tagxyBase = basePosition + new float2(-16, 2); // Correct for the offset in the shp file
- var tagxyOffset = new float2(0, 0); // Correct for offset due to multiple rows
-
- foreach (var tags in self.TraitsImplementing())
- {
- foreach (var tag in tags.GetTags())
- {
- if (tag == TagType.None)
- continue;
-
- var tagImages = new Animation("pips");
- tagImages.PlayRepeating(tagStrings[(int)tag]);
- tagImages.Image.DrawAt(wr, tagxyBase + tagxyOffset, "chrome");
-
- // Increment row
- tagxyOffset.Y += 8;
- }
- }
- }
-
void DrawUnitPath(Actor self)
{
if (self.World.LocalPlayer == null ||!self.World.LocalPlayer.PlayerActor.Trait().PathDebug) return;
diff --git a/OpenRA.Game/Traits/SelectionDecorations.cs b/OpenRA.Game/Traits/SelectionDecorations.cs
new file mode 100644
index 0000000000..8b58d75b15
--- /dev/null
+++ b/OpenRA.Game/Traits/SelectionDecorations.cs
@@ -0,0 +1,116 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2011 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 COPYING.
+ */
+#endregion
+
+using System.Drawing;
+using System.Linq;
+using OpenRA.Graphics;
+
+namespace OpenRA.Traits
+{
+ public class SelectionDecorationsInfo : TraitInfo {}
+
+ public class SelectionDecorations : IPostRenderSelection
+ {
+ // depends on the order of pips in TraitsInterfaces.cs!
+ static readonly string[] pipStrings = { "pip-empty", "pip-green", "pip-yellow", "pip-red", "pip-gray", "pip-blue" };
+ static readonly string[] tagStrings = { "", "tag-fake", "tag-primary" };
+
+ public void RenderAfterWorld (WorldRenderer wr, Actor self)
+ {
+ var bounds = self.Bounds.Value;
+
+ var xy = new float2(bounds.Left, bounds.Top);
+ var xY = new float2(bounds.Left, bounds.Bottom);
+
+ DrawControlGroup(wr, self, xy);
+ DrawPips(wr, self, xY);
+ DrawTags(wr, self, new float2(.5f * (bounds.Left + bounds.Right), bounds.Top));
+ }
+
+ void DrawControlGroup(WorldRenderer wr, Actor self, float2 basePosition)
+ {
+ var group = self.World.Selection.GetControlGroupForActor(self);
+ if (group == null) return;
+
+ var pipImages = new Animation("pips");
+ pipImages.PlayFetchIndex("groups", () => (int)group);
+ pipImages.Tick();
+ pipImages.Image.DrawAt(wr, basePosition + new float2(-8, 1), "chrome");
+ }
+
+ void DrawPips(WorldRenderer wr, Actor self, float2 basePosition)
+ {
+ if (self.Owner != self.World.LocalPlayer) return;
+
+ var pipSources = self.TraitsImplementing();
+ if (pipSources.Count() == 0)
+ return;
+
+ var pipImages = new Animation("pips");
+ pipImages.PlayRepeating(pipStrings[0]);
+
+ var pipSize = pipImages.Image.size;
+ var pipxyBase = basePosition + new float2(1, -pipSize.Y);
+ var pipxyOffset = new float2(0, 0); // Correct for offset due to multiple columns/rows
+
+ foreach (var pips in pipSources)
+ {
+ var thisRow = pips.GetPips(self);
+ if (thisRow == null)
+ continue;
+
+ var width = self.Bounds.Value.Width;
+
+ foreach (var pip in thisRow)
+ {
+ if (pipxyOffset.X + pipSize.X >= width)
+ {
+ pipxyOffset.X = 0;
+ pipxyOffset.Y -= pipSize.Y;
+ }
+ pipImages.PlayRepeating(pipStrings[(int)pip]);
+ pipImages.Image.DrawAt(wr, pipxyBase + pipxyOffset, "chrome");
+ pipxyOffset += new float2(pipSize.X, 0);
+ }
+
+ // Increment row
+ pipxyOffset.X = 0;
+ pipxyOffset.Y -= pipSize.Y + 1;
+ }
+ }
+
+ void DrawTags(WorldRenderer wr, Actor self, float2 basePosition)
+ {
+ if (self.Owner != self.World.LocalPlayer) return;
+
+ // If a mod wants to implement a unit with multiple tags, then they are placed on multiple rows
+ var tagxyBase = basePosition + new float2(-16, 2); // Correct for the offset in the shp file
+ var tagxyOffset = new float2(0, 0); // Correct for offset due to multiple rows
+
+ foreach (var tags in self.TraitsImplementing())
+ {
+ foreach (var tag in tags.GetTags())
+ {
+ if (tag == TagType.None)
+ continue;
+
+ var tagImages = new Animation("pips");
+ tagImages.PlayRepeating(tagStrings[(int)tag]);
+ tagImages.Image.DrawAt(wr, tagxyBase + tagxyOffset, "chrome");
+
+ // Increment row
+ tagxyOffset.Y += 8;
+ }
+ }
+ }
+
+ }
+}
+
diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml
index 590a3a35b4..604ef76559 100644
--- a/mods/cnc/rules/defaults.yaml
+++ b/mods/cnc/rules/defaults.yaml
@@ -10,6 +10,7 @@
BlueTiberium: 40
Beach: 40
ROT: 5
+ SelectionDecorations:
Selectable:
Voice: VehicleVoice
TargetableUnit:
@@ -43,6 +44,7 @@
BlueTiberium: 70
Beach: 70
ROT: 5
+ SelectionDecorations:
Selectable:
Voice: VehicleVoice
TargetableUnit:
@@ -69,6 +71,7 @@
UseLocation: yes
TargetableUnit:
TargetTypes: Air
+ SelectionDecorations:
Selectable:
Voice: VehicleVoice
Helicopter:
@@ -106,6 +109,7 @@
BlueTiberium: 70
PathingCost: 1000
Beach: 80
+ SelectionDecorations:
Selectable:
Voice: GenericVoice
TargetableUnit:
@@ -135,6 +139,7 @@
-TakeCover:
-RenderInfantryProne:
AppearsOnRadar:
+ SelectionDecorations:
Selectable:
Voice: CivilianMaleVoice
Bounds: 12,17,0,-9
@@ -162,6 +167,7 @@
^Plane:
AppearsOnRadar:
UseLocation: yes
+ SelectionDecorations:
Selectable:
Voice: GenericVoice
TargetableUnit:
@@ -179,6 +185,7 @@
Crushes: crate
TerrainSpeeds:
Water: 100
+ SelectionDecorations:
Selectable:
Voice: GenericVoice
TargetableUnit:
@@ -193,6 +200,7 @@
^Building:
AppearsOnRadar:
+ SelectionDecorations:
Selectable:
Priority: 3
TargetableBuilding:
@@ -304,6 +312,7 @@
CrushSound: sandbag2.aud
LineBuild:
Range: 8
+ SelectionDecorations:
Selectable:
Priority: 1
RenderBuildingWall:
diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml
index 76459dea20..41b032f932 100644
--- a/mods/ra/rules/defaults.yaml
+++ b/mods/ra/rules/defaults.yaml
@@ -9,6 +9,7 @@
Ore: 70
Beach: 40
ROT: 5
+ SelectionDecorations:
Selectable:
Voice: VehicleVoice
TargetableUnit:
@@ -43,6 +44,7 @@
Ore: 70
Beach: 70
ROT: 5
+ SelectionDecorations:
Selectable:
Voice: VehicleVoice
TargetableUnit:
@@ -83,6 +85,7 @@
Road: 100
Ore: 80
Beach: 80
+ SelectionDecorations:
Selectable:
Voice: GenericVoice
TargetableUnit:
@@ -115,6 +118,7 @@
Crushes: crate
TerrainSpeeds:
Water: 100
+ SelectionDecorations:
Selectable:
Voice: ShipVoice
TargetableUnit:
@@ -138,6 +142,7 @@
^Plane:
AppearsOnRadar:
UseLocation: yes
+ SelectionDecorations:
Selectable:
Voice: GenericVoice
TargetableAircraft:
@@ -169,6 +174,7 @@
^Building:
AppearsOnRadar:
+ SelectionDecorations:
Selectable:
Priority: 3
TargetableBuilding:
@@ -216,6 +222,7 @@
CrushClasses: wall
LineBuild:
Range: 8
+ SelectionDecorations:
Selectable:
Priority: 1
TargetableBuilding: