diff --git a/OpenRA.Mods.Common/Traits/Buildings/RallyPoint.cs b/OpenRA.Mods.Common/Traits/Buildings/RallyPoint.cs index 0386901635..37a0abf502 100644 --- a/OpenRA.Mods.Common/Traits/Buildings/RallyPoint.cs +++ b/OpenRA.Mods.Common/Traits/Buildings/RallyPoint.cs @@ -48,6 +48,9 @@ namespace OpenRA.Mods.Common.Traits [Desc("The speech notification to play when setting a new rallypoint.")] public readonly string Notification = null; + [Desc("Used to group equivalent actors to allow force-setting a rallypoint (e.g. for Primary production).")] + public readonly string ForceSetType = null; + public override object Create(ActorInitializer init) { return new RallyPoint(init.Self, this); } } @@ -89,7 +92,7 @@ namespace OpenRA.Mods.Common.Traits public IEnumerable Orders { - get { yield return new RallyPointOrderTargeter(Info.Cursor); } + get { yield return new RallyPointOrderTargeter(Info); } } public Order IssueOrder(Actor self, IOrderTargeter order, in Target target, bool queued) @@ -126,11 +129,11 @@ namespace OpenRA.Mods.Common.Traits class RallyPointOrderTargeter : IOrderTargeter { - readonly string cursor; + readonly RallyPointInfo info; - public RallyPointOrderTargeter(string cursor) + public RallyPointOrderTargeter(RallyPointInfo info) { - this.cursor = cursor; + this.info = info; } public string OrderID => "SetRallyPoint"; @@ -149,14 +152,18 @@ namespace OpenRA.Mods.Common.Traits var location = self.World.Map.CellContaining(target.CenterPosition); if (self.World.Map.Contains(location)) { - cursor = this.cursor; + cursor = info.Cursor; - // Notify force-set 'RallyPoint' order watchers with Ctrl and only if this is the only building of its type selected - if (modifiers.HasModifier(TargetModifiers.ForceAttack)) + // Notify force-set 'RallyPoint' order watchers with Ctrl + if (modifiers.HasModifier(TargetModifiers.ForceAttack) && !string.IsNullOrEmpty(info.ForceSetType)) { - var selfName = self.Info.Name; - if (!self.World.Selection.Actors.Any(a => a.Info.Name == selfName && a.ActorID != self.ActorID)) - ForceSet = true; + var closest = self.World.Selection.Actors + .Select(a => (a, a.TraitOrDefault())) + .Where(x => x.RallyPoint != null && x.RallyPoint.Info.ForceSetType == info.ForceSetType) + .OrderBy(x => (location - x.Actor.Location).LengthSquared) + .FirstOrDefault().Actor; + + ForceSet = closest == self; } return true; diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml index 5898d54144..f04117fc65 100644 --- a/mods/d2k/rules/structures.yaml +++ b/mods/d2k/rules/structures.yaml @@ -185,6 +185,7 @@ barracks: RevealsShroud: Range: 3c768 RallyPoint: + ForceSetType: Infantry Exit@1: SpawnOffset: 352,576,0 ExitCell: 0,2 @@ -392,6 +393,7 @@ light_factory: Queues: Vehicle Sequence: production-welding RallyPoint: + ForceSetType: Vehicle Exit@1: SpawnOffset: 544,-224,0 ExitCell: 2,1 @@ -459,6 +461,7 @@ heavy_factory: RevealsShroud: Range: 4c768 RallyPoint: + ForceSetType: Armor Exit@1: SpawnOffset: 256,192,0 ExitCell: 0,2 @@ -595,6 +598,7 @@ starport: RevealsShroud: Range: 3c768 RallyPoint: + ForceSetType: Starport Exit@1: SpawnOffset: 0,-480,0 ExitCell: 2,2 diff --git a/mods/ra/rules/structures.yaml b/mods/ra/rules/structures.yaml index 3119bc9d31..1434075bb4 100644 --- a/mods/ra/rules/structures.yaml +++ b/mods/ra/rules/structures.yaml @@ -208,6 +208,7 @@ SPEN: FinishRepairingNotification: UnitRepaired PlayerExperience: 15 RallyPoint: + ForceSetType: Ship ProductionBar: ProductionType: Ship Power: @@ -322,6 +323,7 @@ SYRD: FinishRepairingNotification: UnitRepaired PlayerExperience: 15 RallyPoint: + ForceSetType: Ship ProductionBar: ProductionType: Ship Power: @@ -1030,6 +1032,7 @@ WEAP: RequiresCondition: !build-incomplete Sequence: build-top RallyPoint: + ForceSetType: Vehicle Exit@1: RequiresCondition: !being-captured SpawnOffset: 213,-128,0 @@ -1386,6 +1389,7 @@ HPAD: ExitCell: 0,0 Facing: 896 RallyPoint: + ForceSetType: Helicopter Production: Produces: Aircraft, Helicopter Reservable: @@ -1467,6 +1471,7 @@ AFLD: ExitCell: 1,1 Facing: 768 RallyPoint: + ForceSetType: Plane Production: Produces: Aircraft, Plane Reservable: @@ -1732,6 +1737,7 @@ BARR: Range: 4c0 WithBuildingBib: RallyPoint: + ForceSetType: Infantry Exit@1: RequiresCondition: !being-captured SpawnOffset: -170,810,0 @@ -1807,6 +1813,7 @@ KENN: WithBuildingBib: HasMinibib: True RallyPoint: + ForceSetType: Dog Exit@0: RequiresCondition: !being-captured SpawnOffset: -280,400,0 @@ -1893,6 +1900,7 @@ TENT: Range: 4c0 WithBuildingBib: RallyPoint: + ForceSetType: Infantry Exit@1: RequiresCondition: !being-captured SpawnOffset: -42,810,0 diff --git a/mods/ts/rules/gdi-structures.yaml b/mods/ts/rules/gdi-structures.yaml index d870814b3a..7698128de6 100644 --- a/mods/ts/rules/gdi-structures.yaml +++ b/mods/ts/rules/gdi-structures.yaml @@ -133,6 +133,7 @@ GAPILE: Palette: mouse IsPlayerPalette: false LineWidth: 2 + ForceSetType: Infantry Exit@1: SpawnOffset: -512,768,0 ExitCell: 1,2 @@ -226,6 +227,7 @@ GAWEAP: Palette: mouse IsPlayerPalette: false LineWidth: 2 + ForceSetType: Vehicle Exit@1: SpawnOffset: -384,-384,0 ExitCell: 3,1 @@ -303,6 +305,7 @@ GAHPAD: Palette: mouse IsPlayerPalette: false LineWidth: 2 + ForceSetType: Air Production: Produces: Air PauseOnCondition: empdisable diff --git a/mods/ts/rules/nod-structures.yaml b/mods/ts/rules/nod-structures.yaml index 3e0cbec6a0..bd08ab3a64 100644 --- a/mods/ts/rules/nod-structures.yaml +++ b/mods/ts/rules/nod-structures.yaml @@ -159,6 +159,7 @@ NAHAND: Palette: mouse IsPlayerPalette: false LineWidth: 2 + ForceSetType: Infantry Production: Produces: Infantry PauseOnCondition: empdisable @@ -205,6 +206,7 @@ NAWEAP: Palette: mouse IsPlayerPalette: false LineWidth: 2 + ForceSetType: Vehicle Exit@1: SpawnOffset: -384,-384,0 ExitCell: 3,1 @@ -267,6 +269,7 @@ NAHPAD: Palette: mouse IsPlayerPalette: false LineWidth: 2 + ForceSetType: Air Production: Produces: Air PauseOnCondition: empdisable