diff --git a/OpenRA.Mods.Common/Activities/Resupply.cs b/OpenRA.Mods.Common/Activities/Resupply.cs index 9b2f7ddfc9..1470c6ee04 100644 --- a/OpenRA.Mods.Common/Activities/Resupply.cs +++ b/OpenRA.Mods.Common/Activities/Resupply.cs @@ -188,7 +188,8 @@ namespace OpenRA.Mods.Common.Activities if (wasRepaired || isHostInvalid || (!stayOnResupplier && aircraft.Info.TakeOffOnResupply)) { if (self.CurrentActivity.NextActivity == null && rp != null) - QueueChild(move.MoveTo(rp.Location, ignoreActor: repairableNear != null ? null : host.Actor, targetLineColor: Color.Green)); + foreach (var cell in rp.Path) + QueueChild(move.MoveTo(cell, 1, ignoreActor: repairableNear != null ? null : host.Actor, targetLineColor: Color.Green)); else QueueChild(new TakeOff(self)); @@ -208,7 +209,8 @@ namespace OpenRA.Mods.Common.Activities if (self.CurrentActivity.NextActivity == null) { if (rp != null) - QueueChild(move.MoveTo(rp.Location, ignoreActor: repairableNear != null ? null : host.Actor)); + foreach (var cell in rp.Path) + QueueChild(move.MoveTo(cell, 1, repairableNear != null ? null : host.Actor, true)); else if (repairableNear == null) QueueChild(move.MoveToTarget(self, host)); } diff --git a/OpenRA.Mods.Common/Effects/RallyPointIndicator.cs b/OpenRA.Mods.Common/Effects/RallyPointIndicator.cs index cb359fd3ed..61a27894b6 100644 --- a/OpenRA.Mods.Common/Effects/RallyPointIndicator.cs +++ b/OpenRA.Mods.Common/Effects/RallyPointIndicator.cs @@ -25,8 +25,8 @@ namespace OpenRA.Mods.Common.Effects readonly Animation circles; readonly ExitInfo[] exits; - readonly WPos[] targetLine = new WPos[2]; - CPos cachedLocation; + List targetLineNodes = new List { }; + List cachedLocations; public RallyPointIndicator(Actor building, RallyPoint rp, ExitInfo[] exits) { @@ -52,11 +52,13 @@ namespace OpenRA.Mods.Common.Effects if (circles != null) circles.Tick(); - if (cachedLocation != rp.Location) + if (cachedLocations == null || !cachedLocations.SequenceEqual(rp.Path)) { - cachedLocation = rp.Location; + cachedLocations = new List(rp.Path); + targetLineNodes.Clear(); + foreach (var c in cachedLocations) + targetLineNodes.Add(world.Map.CenterOfCell(c)); - var rallyPos = world.Map.CenterOfCell(cachedLocation); var exitPos = building.CenterPosition; // Find closest exit @@ -64,7 +66,7 @@ namespace OpenRA.Mods.Common.Effects foreach (var exit in exits) { var ep = building.CenterPosition + exit.SpawnOffset; - var len = (rallyPos - ep).Length; + var len = (targetLineNodes[0] - ep).Length; if (len < dist) { dist = len; @@ -72,8 +74,7 @@ namespace OpenRA.Mods.Common.Effects } } - targetLine[0] = exitPos; - targetLine[1] = rallyPos; + targetLineNodes.Insert(0, exitPos); if (circles != null) circles.Play(rp.Info.CirclesSequence); @@ -98,10 +99,10 @@ namespace OpenRA.Mods.Common.Effects { var palette = wr.Palette(rp.PaletteName); if (circles != null) - renderables = renderables.Concat(circles.Render(targetLine[1], palette)); + renderables = renderables.Concat(circles.Render(targetLineNodes.Last(), palette)); if (flag != null) - renderables = renderables.Concat(flag.Render(targetLine[1], palette)); + renderables = renderables.Concat(flag.Render(targetLineNodes.Last(), palette)); } return renderables; @@ -118,7 +119,18 @@ namespace OpenRA.Mods.Common.Effects if (!building.World.Selection.Contains(building)) return SpriteRenderable.None; - return new IRenderable[] { new TargetLineRenderable(targetLine, building.Owner.Color, rp.Info.LineWidth) }; + return RenderInner(wr); + } + + IEnumerable RenderInner(WorldRenderer wr) + { + var prev = targetLineNodes[0]; + foreach (var pos in targetLineNodes.Skip(1)) + { + var targetLine = new[] { prev, pos }; + prev = pos; + yield return new TargetLineRenderable(targetLine, building.Owner.Color, rp.Info.LineWidth); + } } } } diff --git a/OpenRA.Mods.Common/Scripting/Properties/ProductionProperties.cs b/OpenRA.Mods.Common/Scripting/Properties/ProductionProperties.cs index 8a3b0a0ec7..a6e648204c 100644 --- a/OpenRA.Mods.Common/Scripting/Properties/ProductionProperties.cs +++ b/OpenRA.Mods.Common/Scripting/Properties/ProductionProperties.cs @@ -79,8 +79,8 @@ namespace OpenRA.Mods.Common.Scripting [Desc("Query or set a factory's rally point.")] public CPos RallyPoint { - get { return rp.Location; } - set { rp.Location = value; } + get { return rp.Path.Last(); } + set { rp.Path = new List { value }; } } } diff --git a/OpenRA.Mods.Common/Traits/BotModules/BaseBuilderBotModule.cs b/OpenRA.Mods.Common/Traits/BotModules/BaseBuilderBotModule.cs index cacc6336a1..e6f698cd74 100644 --- a/OpenRA.Mods.Common/Traits/BotModules/BaseBuilderBotModule.cs +++ b/OpenRA.Mods.Common/Traits/BotModules/BaseBuilderBotModule.cs @@ -229,7 +229,7 @@ namespace OpenRA.Mods.Common.Traits foreach (var rp in world.ActorsWithTrait()) { if (rp.Actor.Owner == player && - !IsRallyPointValid(rp.Trait.Location, rp.Actor.Info.TraitInfoOrDefault())) + !IsRallyPointValid(rp.Trait.Path[0], rp.Actor.Info.TraitInfoOrDefault())) { bot.QueueOrder(new Order("SetRallyPoint", rp.Actor, Target.FromCell(world, ChooseRallyLocationNear(rp.Actor)), false) { diff --git a/OpenRA.Mods.Common/Traits/Buildings/RallyPoint.cs b/OpenRA.Mods.Common/Traits/Buildings/RallyPoint.cs index f66ea71018..32e1f51cb8 100644 --- a/OpenRA.Mods.Common/Traits/Buildings/RallyPoint.cs +++ b/OpenRA.Mods.Common/Traits/Buildings/RallyPoint.cs @@ -48,23 +48,22 @@ namespace OpenRA.Mods.Common.Traits { const string OrderID = "SetRallyPoint"; - [Sync] - public CPos Location; + public List Path; public RallyPointInfo Info; public string PaletteName { get; private set; } const uint ForceSet = 1; - public void ResetLocation(Actor self) + public void ResetPath(Actor self) { - Location = self.Location + Info.Offset; + Path = new List { self.Location + Info.Offset }; } public RallyPoint(Actor self, RallyPointInfo info) { Info = info; - ResetLocation(self); + ResetPath(self); PaletteName = info.IsPlayerPalette ? info.Palette + self.Owner.InternalName : info.Palette; } @@ -84,7 +83,7 @@ namespace OpenRA.Mods.Common.Traits if (Info.IsPlayerPalette) PaletteName = Info.Palette + newOwner.InternalName; - ResetLocation(self); + ResetPath(self); } public IEnumerable Orders @@ -96,7 +95,7 @@ namespace OpenRA.Mods.Common.Traits { if (order.OrderID == OrderID) { - return new Order(order.OrderID, self, target, false) + return new Order(order.OrderID, self, target, queued) { SuppressVisualFeedback = true, ExtraData = ((RallyPointOrderTargeter)order).ForceSet ? ForceSet : 0 @@ -108,8 +107,13 @@ namespace OpenRA.Mods.Common.Traits public void ResolveOrder(Actor self, Order order) { - if (order.OrderString == OrderID) - Location = self.World.Map.CellContaining(order.Target.CenterPosition); + if (order.OrderString != OrderID) + return; + + if (!order.Queued) + Path.Clear(); + + Path.Add(self.World.Map.CellContaining(order.Target.CenterPosition)); } public static bool IsForceSet(Order order) @@ -130,12 +134,15 @@ namespace OpenRA.Mods.Common.Traits public int OrderPriority { get { return 0; } } public bool TargetOverridesSelection(Actor self, Target target, List actorsAt, CPos xy, TargetModifiers modifiers) { return true; } public bool ForceSet { get; private set; } + public bool IsQueued { get; protected set; } public bool CanTarget(Actor self, Target target, List othersAtTarget, ref TargetModifiers modifiers, ref string cursor) { if (target.Type != TargetType.Terrain) return false; + IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue); + var location = self.World.Map.CellContaining(target.CenterPosition); if (self.World.Map.Contains(location)) { @@ -154,8 +161,6 @@ namespace OpenRA.Mods.Common.Traits return false; } - - public bool IsQueued { get { return false; } } // unused } } } diff --git a/OpenRA.Mods.Common/Traits/Buildings/Reservable.cs b/OpenRA.Mods.Common/Traits/Buildings/Reservable.cs index 3b7ae41b46..15c92d7bc7 100644 --- a/OpenRA.Mods.Common/Traits/Buildings/Reservable.cs +++ b/OpenRA.Mods.Common/Traits/Buildings/Reservable.cs @@ -85,7 +85,8 @@ namespace OpenRA.Mods.Common.Traits if (reservedForAircraft.GetActorBelow() == self) { if (rallyPoint != null) - reservedFor.QueueActivity(reservedForAircraft.MoveTo(rallyPoint.Location, null, targetLineColor: Color.Green)); + foreach (var cell in rallyPoint.Path) + reservedFor.QueueActivity(reservedForAircraft.MoveTo(cell, 1, targetLineColor: Color.Green)); else reservedFor.QueueActivity(new TakeOff(reservedFor)); } diff --git a/OpenRA.Mods.Common/Traits/Production.cs b/OpenRA.Mods.Common/Traits/Production.cs index 68149dd18d..b78dfa89a9 100644 --- a/OpenRA.Mods.Common/Traits/Production.cs +++ b/OpenRA.Mods.Common/Traits/Production.cs @@ -10,6 +10,7 @@ #endregion using System; +using System.Collections.Generic; using OpenRA.Mods.Common.Activities; using OpenRA.Primitives; using OpenRA.Traits; @@ -42,7 +43,7 @@ namespace OpenRA.Mods.Common.Traits public virtual void DoProduction(Actor self, ActorInfo producee, ExitInfo exitinfo, string productionType, TypeDictionary inits) { var exit = CPos.Zero; - var exitLocation = CPos.Zero; + var exitLocations = new List(); // Clone the initializer dictionary for the new actor var td = new TypeDictionary(); @@ -68,7 +69,7 @@ namespace OpenRA.Mods.Common.Traits initialFacing = delta.Yaw.Facing; } - exitLocation = rp.Value != null ? rp.Value.Location : exit; + exitLocations = rp.Value != null ? rp.Value.Path : new List { exit }; td.Add(new LocationInit(exit)); td.Add(new CenterPositionInit(spawn)); @@ -83,7 +84,8 @@ namespace OpenRA.Mods.Common.Traits var move = newUnit.TraitOrDefault(); if (exitinfo != null && move != null) - newUnit.QueueActivity(new AttackMoveActivity(newUnit, () => move.MoveTo(exitLocation, 1, targetLineColor: Color.OrangeRed))); + foreach (var cell in exitLocations) + newUnit.QueueActivity(new AttackMoveActivity(newUnit, () => move.MoveTo(cell, 1, evaluateNearestMovableCell: true, targetLineColor: Color.OrangeRed))); if (!self.IsDead) foreach (var t in self.TraitsImplementing()) diff --git a/OpenRA.Mods.Common/Traits/ProductionFromMapEdge.cs b/OpenRA.Mods.Common/Traits/ProductionFromMapEdge.cs index 4cd5b379e6..c6eb9ddedd 100644 --- a/OpenRA.Mods.Common/Traits/ProductionFromMapEdge.cs +++ b/OpenRA.Mods.Common/Traits/ProductionFromMapEdge.cs @@ -9,8 +9,8 @@ */ #endregion +using System.Collections.Generic; using OpenRA.Primitives; -using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { @@ -49,7 +49,7 @@ namespace OpenRA.Mods.Common.Traits var aircraftInfo = producee.TraitInfoOrDefault(); var mobileInfo = producee.TraitInfoOrDefault(); - var destination = rp != null ? rp.Location : self.Location; + var destinations = rp != null ? rp.Path : new List { self.Location }; var location = spawnLocation; if (!location.HasValue) @@ -61,7 +61,7 @@ namespace OpenRA.Mods.Common.Traits { var locomotorInfo = mobileInfo.LocomotorInfo; location = self.World.Map.ChooseClosestMatchingEdgeCell(self.Location, - c => mobileInfo.CanEnterCell(self.World, null, c) && domainIndex.IsPassable(c, destination, locomotorInfo)); + c => mobileInfo.CanEnterCell(self.World, null, c) && domainIndex.IsPassable(c, destinations[0], locomotorInfo)); } } @@ -75,7 +75,7 @@ namespace OpenRA.Mods.Common.Traits if (aircraftInfo != null) pos += new WVec(0, 0, aircraftInfo.CruiseAltitude.Length); - var initialFacing = self.World.Map.FacingBetween(location.Value, destination, 0); + var initialFacing = self.World.Map.FacingBetween(location.Value, destinations[0], 0); self.World.AddFrameEndTask(w => { @@ -91,11 +91,12 @@ namespace OpenRA.Mods.Common.Traits var move = newUnit.TraitOrDefault(); if (move != null) - newUnit.QueueActivity(move.MoveTo(destination, 2)); + foreach (var cell in destinations) + newUnit.QueueActivity(move.MoveTo(cell, 2, evaluateNearestMovableCell: true)); if (!self.IsDead) foreach (var t in self.TraitsImplementing()) - t.UnitProduced(self, newUnit, destination); + t.UnitProduced(self, newUnit, destinations[0]); var notifyOthers = self.World.ActorsWithTrait(); foreach (var notify in notifyOthers) diff --git a/OpenRA.Mods.Common/Traits/ProductionParadrop.cs b/OpenRA.Mods.Common/Traits/ProductionParadrop.cs index caba158fa2..966142f0c9 100644 --- a/OpenRA.Mods.Common/Traits/ProductionParadrop.cs +++ b/OpenRA.Mods.Common/Traits/ProductionParadrop.cs @@ -10,6 +10,7 @@ #endregion using System; +using System.Collections.Generic; using OpenRA.Activities; using OpenRA.Mods.Common.Activities; using OpenRA.Primitives; @@ -102,7 +103,7 @@ namespace OpenRA.Mods.Common.Traits public override void DoProduction(Actor self, ActorInfo producee, ExitInfo exitinfo, string productionType, TypeDictionary inits) { var exit = CPos.Zero; - var exitLocation = CPos.Zero; + var exitLocations = new List(); var info = (ProductionParadropInfo)Info; var actorType = info.ActorType; @@ -122,7 +123,7 @@ namespace OpenRA.Mods.Common.Traits var initialFacing = exitinfo.Facing < 0 ? (to - spawn).Yaw.Facing : exitinfo.Facing; - exitLocation = rp.Value != null ? rp.Value.Location : exit; + exitLocations = rp.Value != null ? rp.Value.Path : new List { exit }; td.Add(new LocationInit(exit)); td.Add(new CenterPositionInit(spawn)); @@ -137,7 +138,8 @@ namespace OpenRA.Mods.Common.Traits var move = newUnit.TraitOrDefault(); if (move != null) - newUnit.QueueActivity(new AttackMoveActivity(newUnit, () => move.MoveTo(exitLocation, 1, targetLineColor: Color.OrangeRed))); + foreach (var cell in exitLocations) + newUnit.QueueActivity(new AttackMoveActivity(newUnit, () => move.MoveTo(cell, 1, evaluateNearestMovableCell: true, targetLineColor: Color.OrangeRed))); if (!self.IsDead) foreach (var t in self.TraitsImplementing())