diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj
index 38a07dba6d..2ef2dc70b0 100755
--- a/OpenRA.Game/OpenRA.Game.csproj
+++ b/OpenRA.Game/OpenRA.Game.csproj
@@ -210,6 +210,8 @@
+
+
@@ -251,4 +253,4 @@
-
\ No newline at end of file
+
diff --git a/OpenRA.Game/Traits/BaseBuilding.cs b/OpenRA.Game/Traits/BaseBuilding.cs
deleted file mode 100755
index 548e4bb308..0000000000
--- a/OpenRA.Game/Traits/BaseBuilding.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-#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 OpenRA.Traits;
-
-namespace OpenRA.Traits
-{
- /* tag trait for "bases": mcv/fact */
- public class BaseBuildingInfo : TraitInfo { }
- public class BaseBuilding { }
-}
diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs
index 57ce0dd58d..803671a9a2 100755
--- a/OpenRA.Game/Traits/TraitsInterfaces.cs
+++ b/OpenRA.Game/Traits/TraitsInterfaces.cs
@@ -241,4 +241,6 @@ namespace OpenRA.Traits
string[] TargetTypes { get; }
IEnumerable TargetableCells( Actor self );
}
+
+ public interface INotifyKeyPress { bool KeyPressed(Actor self, KeyInput e); }
}
diff --git a/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs b/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs
index 193254fcfd..843dcda366 100644
--- a/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs
+++ b/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs
@@ -134,13 +134,14 @@ namespace OpenRA.Widgets
{
world.Selection.DoControlGroup(world, e.KeyName[0] - '0', e.Modifiers);
return true;
- }
-
- if (e.KeyChar == '\b' || e.KeyChar == (char)127)
- {
- GotoNextBase();
- return true;
- }
+ }
+
+ bool handled = false;
+
+ foreach (var t in world.WorldActor.TraitsImplementing())
+ handled = (t.KeyPressed(world.WorldActor, e)) ? true : handled;
+
+ if (handled) return true;
if (e.KeyChar == 'a')
{
@@ -157,24 +158,6 @@ namespace OpenRA.Widgets
world.OrderGenerator = new GenericSelectTarget(world.Selection.Actors, "AttackMove", "attackmove");
}
- public void GotoNextBase()
- {
- var bases = world.Queries.OwnedBy[world.LocalPlayer].WithTrait().ToArray();
- if (!bases.Any()) return;
-
- var next = bases
- .Select( b => b.Actor )
- .SkipWhile(b => !world.Selection.Actors.Contains(b))
- .Skip(1)
- .FirstOrDefault();
-
- if (next == null)
- next = bases.Select(b => b.Actor).First();
-
- world.Selection.Combine(world, new Actor[] { next }, false, true);
- Game.viewport.Center(world.Selection.Actors);
- }
-
IEnumerable SelectActorsInBox(World world, float2 a, float2 b)
{
return world.FindUnits(a, b)
diff --git a/OpenRA.Mods.RA/BaseBuilding.cs b/OpenRA.Mods.RA/BaseBuilding.cs
new file mode 100644
index 0000000000..83780c82f0
--- /dev/null
+++ b/OpenRA.Mods.RA/BaseBuilding.cs
@@ -0,0 +1,8 @@
+using OpenRA.Traits;
+
+namespace OpenRA.Mods.RA
+{
+ /* tag trait for "bases": mcv/fact */
+ public class BaseBuildingInfo : TraitInfo { }
+ public class BaseBuilding { }
+}
diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj
index d78da20152..07f2d1c8bd 100644
--- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj
+++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj
@@ -82,6 +82,7 @@
+
@@ -288,6 +289,7 @@
+
diff --git a/OpenRA.Mods.RA/World/GotoNextBase.cs b/OpenRA.Mods.RA/World/GotoNextBase.cs
new file mode 100644
index 0000000000..fe77db1715
--- /dev/null
+++ b/OpenRA.Mods.RA/World/GotoNextBase.cs
@@ -0,0 +1,44 @@
+using System.Linq;
+using OpenRA.Traits;
+
+namespace OpenRA.Mods.RA
+{
+ public class GotoNextBaseInfo : TraitInfo
+ {
+
+ }
+
+ public class GotoNextBase : INotifyKeyPress
+ {
+ public bool KeyPressed(Actor self, KeyInput e)
+ {
+ if (self.World.LocalPlayer == null) return false;
+
+ if (e.KeyChar == '\b' || e.KeyChar == (char)127)
+ {
+ CycleBases(self.World);
+ return true;
+ }
+
+ return false;
+ }
+
+ public static void CycleBases(World world)
+ {
+ var bases = world.Queries.OwnedBy[world.LocalPlayer].WithTrait().ToArray();
+ if (!bases.Any()) return;
+
+ var next = bases
+ .Select(b => b.Actor)
+ .SkipWhile(b => !world.Selection.Actors.Contains(b))
+ .Skip(1)
+ .FirstOrDefault();
+
+ if (next == null)
+ next = bases.Select(b => b.Actor).First();
+
+ world.Selection.Combine(world, new Actor[] { next }, false, true);
+ Game.viewport.Center(world.Selection.Actors);
+ }
+ }
+}
diff --git a/mods/cnc/rules/system.yaml b/mods/cnc/rules/system.yaml
index affe4cf69c..da55c0265f 100644
--- a/mods/cnc/rules/system.yaml
+++ b/mods/cnc/rules/system.yaml
@@ -183,6 +183,7 @@ World:
WaterChance: 0
PathFinder:
ValidateOrder:
+ GotoNextBase:
CRATE:
Tooltip:
diff --git a/mods/ra/rules/system.yaml b/mods/ra/rules/system.yaml
index 88c998962c..c18c7f609e 100644
--- a/mods/ra/rules/system.yaml
+++ b/mods/ra/rules/system.yaml
@@ -227,6 +227,7 @@ World:
ReturnToLobby: yes
EndMessage: The game will end in {0} seconds.
ValidateOrder:
+ GotoNextBase:
MINP:
Mine: