diff --git a/OpenRA.Mods.Common/Activities/Air/TakeOff.cs b/OpenRA.Mods.Common/Activities/Air/TakeOff.cs index 989f2bc6f5..10f37734b2 100644 --- a/OpenRA.Mods.Common/Activities/Air/TakeOff.cs +++ b/OpenRA.Mods.Common/Activities/Air/TakeOff.cs @@ -53,9 +53,9 @@ namespace OpenRA.Mods.Common.Activities (hasHost ? self.World.Map.CellContaining(host.CenterPosition) : self.Location); if (moveToRallyPoint(self, this, destination)) - return new AttackMoveActivity(self, move.MoveTo(destination, 1)); - else - return NextActivity; + return new AttackMoveActivity(self, () => move.MoveTo(destination, 1)); + + return NextActivity; } } } diff --git a/OpenRA.Mods.Common/Activities/Hunt.cs b/OpenRA.Mods.Common/Activities/Hunt.cs index bf246e3e73..0a0dafe4ee 100644 --- a/OpenRA.Mods.Common/Activities/Hunt.cs +++ b/OpenRA.Mods.Common/Activities/Hunt.cs @@ -41,7 +41,7 @@ namespace OpenRA.Mods.Common.Activities return this; return ActivityUtils.SequenceActivities(self, - new AttackMoveActivity(self, move.MoveTo(target.Location, 2)), + new AttackMoveActivity(self, () => move.MoveTo(target.Location, 2)), new Wait(25), this); } diff --git a/OpenRA.Mods.Common/Activities/Move/AttackMoveActivity.cs b/OpenRA.Mods.Common/Activities/Move/AttackMoveActivity.cs index 538761e7b1..624ca90fb2 100644 --- a/OpenRA.Mods.Common/Activities/Move/AttackMoveActivity.cs +++ b/OpenRA.Mods.Common/Activities/Move/AttackMoveActivity.cs @@ -9,6 +9,7 @@ */ #endregion +using System; using System.Collections.Generic; using OpenRA.Activities; using OpenRA.Mods.Common.Traits; @@ -18,31 +19,75 @@ namespace OpenRA.Mods.Common.Activities { public class AttackMoveActivity : Activity { - const int ScanInterval = 7; - + readonly Func getInner; + public readonly bool IsAssaultMove; Activity inner; - int scanTicks; + Activity attack; AutoTarget autoTarget; + bool moving; - public AttackMoveActivity(Actor self, Activity inner) + public AttackMoveActivity(Actor self, Func getInner, bool assaultMoving = false) { - this.inner = inner; + this.getInner = getInner; autoTarget = self.TraitOrDefault(); + moving = false; + IsAssaultMove = assaultMoving; } public override Activity Tick(Actor self) { - if (autoTarget != null && --scanTicks <= 0) + if (IsCanceling) { - autoTarget.ScanAndAttack(self, true); - scanTicks = ScanInterval; + if (attack != null) + { + attack = ActivityUtils.RunActivity(self, attack); + return this; + } + + if (inner != null) + { + inner = ActivityUtils.RunActivity(self, inner); + return this; + } + + return NextActivity; + } + + if (attack == null && autoTarget != null) + { + var target = autoTarget.ScanForTarget(self, true); + if (target.Type != TargetType.Invalid) + { + if (inner != null) + inner.Cancel(self); + + var attackBases = autoTarget.ActiveAttackBases; + foreach (var ab in attackBases) + { + if (attack == null) + attack = ab.GetAttackActivity(self, target, true, false); + else + attack = ActivityUtils.SequenceActivities(self, attack, ab.GetAttackActivity(self, target, true, false)); + ab.OnQueueAttackActivity(self, target, false, true, false); + } + + moving = false; + } + } + + if (attack == null && inner == null) + { + if (moving) + return NextActivity; + + inner = getInner(); + moving = true; } if (inner == null) - return NextActivity; + attack = ActivityUtils.RunActivity(self, attack); inner = ActivityUtils.RunActivity(self, inner); - return this; } @@ -51,6 +96,9 @@ namespace OpenRA.Mods.Common.Activities if (!IsCanceling && inner != null) inner.Cancel(self); + if (!IsCanceling && attack != null) + attack.Cancel(self); + base.Cancel(self, keepQueue); } diff --git a/OpenRA.Mods.Common/Scripting/Properties/CombatProperties.cs b/OpenRA.Mods.Common/Scripting/Properties/CombatProperties.cs index 99eb60ecde..e6a98abde2 100644 --- a/OpenRA.Mods.Common/Scripting/Properties/CombatProperties.cs +++ b/OpenRA.Mods.Common/Scripting/Properties/CombatProperties.cs @@ -9,6 +9,7 @@ */ #endregion +using System; using System.Linq; using Eluant; using OpenRA.Activities; @@ -43,7 +44,7 @@ namespace OpenRA.Mods.Common.Scripting "close enough to complete the activity.")] public void AttackMove(CPos cell, int closeEnough = 0) { - Self.QueueActivity(new AttackMoveActivity(Self, move.MoveTo(cell, closeEnough))); + Self.QueueActivity(new AttackMoveActivity(Self, () => move.MoveTo(cell, closeEnough))); } [ScriptActorPropertyActivity] @@ -53,7 +54,7 @@ namespace OpenRA.Mods.Common.Scripting { foreach (var wpt in waypoints) { - Self.QueueActivity(new AttackMoveActivity(Self, move.MoveTo(wpt, 2))); + Self.QueueActivity(new AttackMoveActivity(Self, () => move.MoveTo(wpt, 2))); Self.QueueActivity(new Wait(wait)); } diff --git a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs index fdaedc333d..e43528c707 100644 --- a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs +++ b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs @@ -163,7 +163,7 @@ namespace OpenRA.Mods.Common.Traits } public class Aircraft : ITick, ISync, IFacing, IPositionable, IMove, IIssueOrder, IResolveOrder, IOrderVoice, IDeathActorInitModifier, - INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyActorDisposing, INotifyBecomingIdle, + INotifyCreated, INotifyAddedToWorld, INotifyRemovedFromWorld, INotifyActorDisposing, IActorPreviewInitModifier, IIssueDeployOrder, IObservesVariables { static readonly Pair[] NoCells = { }; @@ -173,7 +173,6 @@ namespace OpenRA.Mods.Common.Traits RepairableInfo repairableInfo; RearmableInfo rearmableInfo; - AttackMove attackMove; ConditionManager conditionManager; IDisposable reservation; IEnumerable speedModifiers; @@ -231,7 +230,6 @@ namespace OpenRA.Mods.Common.Traits { repairableInfo = self.Info.TraitInfoOrDefault(); rearmableInfo = self.Info.TraitInfoOrDefault(); - attackMove = self.TraitOrDefault(); conditionManager = self.TraitOrDefault(); speedModifiers = self.TraitsImplementing().ToArray().Select(sm => sm.GetSpeedModifier()); cachedPosition = self.CenterPosition; @@ -521,16 +519,6 @@ namespace OpenRA.Mods.Common.Traits init.Add(new FacingInit(Facing)); } - void INotifyBecomingIdle.OnBecomingIdle(Actor self) - { - // HACK: Work around AttackMove relying on INotifyIdle.TickIdle to continue its path - // AttackMoveActivity needs to be rewritten to use child activities instead! - if (attackMove != null && attackMove.TargetLocation.HasValue) - ((INotifyIdle)attackMove).TickIdle(self); - else - OnBecomingIdle(self); - } - protected virtual void OnBecomingIdle(Actor self) { if (Info.VTOL && Info.LandWhenIdle) diff --git a/OpenRA.Mods.Common/Traits/AttackMove.cs b/OpenRA.Mods.Common/Traits/AttackMove.cs index 0a5b676e43..44a28ab3fd 100644 --- a/OpenRA.Mods.Common/Traits/AttackMove.cs +++ b/OpenRA.Mods.Common/Traits/AttackMove.cs @@ -38,19 +38,14 @@ namespace OpenRA.Mods.Common.Traits public object Create(ActorInitializer init) { return new AttackMove(init.Self, this); } } - class AttackMove : INotifyCreated, ITick, IResolveOrder, IOrderVoice, INotifyIdle, ISync + class AttackMove : INotifyCreated, ITick, IResolveOrder, IOrderVoice, ISync { public readonly AttackMoveInfo Info; - - [Sync] public CPos _targetLocation { get { return TargetLocation.HasValue ? TargetLocation.Value : CPos.Zero; } } - public CPos? TargetLocation = null; - readonly IMove move; ConditionManager conditionManager; int attackMoveToken = ConditionManager.InvalidConditionToken; int assaultMoveToken = ConditionManager.InvalidConditionToken; - bool assaultMoving = false; public AttackMove(Actor self, AttackMoveInfo info) { @@ -69,8 +64,8 @@ namespace OpenRA.Mods.Common.Traits return; var activity = self.CurrentActivity as AttackMoveActivity; - var attackActive = activity != null && !assaultMoving; - var assaultActive = activity != null && assaultMoving; + var attackActive = activity != null && !activity.IsAssaultMove; + var assaultActive = activity != null && activity.IsAssaultMove; if (attackActive && attackMoveToken == ConditionManager.InvalidConditionToken && !string.IsNullOrEmpty(Info.AttackMoveScanCondition)) attackMoveToken = conditionManager.GrantCondition(self, Info.AttackMoveScanCondition); @@ -98,23 +93,8 @@ namespace OpenRA.Mods.Common.Traits return null; } - void Activate(Actor self, bool assaultMove) - { - assaultMoving = assaultMove; - self.QueueActivity(new AttackMoveActivity(self, move.MoveTo(TargetLocation.Value, 1))); - } - - void INotifyIdle.TickIdle(Actor self) - { - // This might cause the actor to be stuck if the target location is unreachable - if (TargetLocation.HasValue && self.Location != TargetLocation.Value) - Activate(self, assaultMoving); - } - public void ResolveOrder(Actor self, Order order) { - TargetLocation = null; - if (order.OrderString == "AttackMove" || order.OrderString == "AssaultMove") { if (!order.Queued) @@ -124,9 +104,10 @@ namespace OpenRA.Mods.Common.Traits if (!Info.MoveIntoShroud && !self.Owner.Shroud.IsExplored(cell)) return; - TargetLocation = move.NearestMoveableCell(cell); - self.SetTargetLine(Target.FromCell(self.World, TargetLocation.Value), Color.Red); - Activate(self, order.OrderString == "AssaultMove"); + var targetLocation = move.NearestMoveableCell(cell); + self.SetTargetLine(Target.FromCell(self.World, targetLocation), Color.Red); + var assaultMoving = order.OrderString == "AssaultMove"; + self.QueueActivity(new AttackMoveActivity(self, () => move.MoveTo(targetLocation, 1), assaultMoving)); } } } diff --git a/OpenRA.Mods.Common/Traits/AutoTarget.cs b/OpenRA.Mods.Common/Traits/AutoTarget.cs index b41436ada5..ec8aedeca3 100644 --- a/OpenRA.Mods.Common/Traits/AutoTarget.cs +++ b/OpenRA.Mods.Common/Traits/AutoTarget.cs @@ -110,7 +110,7 @@ namespace OpenRA.Mods.Common.Traits public class AutoTarget : ConditionalTrait, INotifyIdle, INotifyDamage, ITick, IResolveOrder, ISync, INotifyCreated, INotifyOwnerChanged { - readonly IEnumerable activeAttackBases; + public readonly IEnumerable ActiveAttackBases; [Sync] int nextScanTime = 0; public UnitStance Stance { get { return stance; } } @@ -151,7 +151,7 @@ namespace OpenRA.Mods.Common.Traits : base(info) { var self = init.Self; - activeAttackBases = self.TraitsImplementing().ToArray().Where(Exts.IsTraitEnabled); + ActiveAttackBases = self.TraitsImplementing().ToArray().Where(Exts.IsTraitEnabled); if (init.Contains()) stance = init.Get(); @@ -209,7 +209,7 @@ namespace OpenRA.Mods.Common.Traits // Not a lot we can do about things we can't hurt... although maybe we should automatically run away? var attackerAsTarget = Target.FromActor(attacker); - if (!activeAttackBases.Any(a => a.HasAnyValidWeapons(attackerAsTarget))) + if (!ActiveAttackBases.Any(a => a.HasAnyValidWeapons(attackerAsTarget))) return; // Don't retaliate against own units force-firing on us. It's usually not what the player wanted. @@ -242,11 +242,11 @@ namespace OpenRA.Mods.Common.Traits public Target ScanForTarget(Actor self, bool allowMove) { - if (nextScanTime <= 0 && activeAttackBases.Any()) + if (nextScanTime <= 0 && ActiveAttackBases.Any()) { nextScanTime = self.World.SharedRandom.Next(Info.MinimumScanTimeInterval, Info.MaximumScanTimeInterval); - foreach (var ab in activeAttackBases) + foreach (var ab in ActiveAttackBases) { // If we can't attack right now, there's no need to try and find a target. var attackStances = ab.UnforcedAttackTargetStances(); @@ -272,7 +272,7 @@ namespace OpenRA.Mods.Common.Traits { self.SetTargetLine(target, Color.Red, false); - foreach (var ab in activeAttackBases) + foreach (var ab in ActiveAttackBases) ab.AttackTarget(target, false, allowMove); } diff --git a/OpenRA.Mods.Common/Traits/Guard.cs b/OpenRA.Mods.Common/Traits/Guard.cs index 54160ec5c9..e12131d61d 100644 --- a/OpenRA.Mods.Common/Traits/Guard.cs +++ b/OpenRA.Mods.Common/Traits/Guard.cs @@ -55,7 +55,7 @@ namespace OpenRA.Mods.Common.Traits self.SetTargetLine(target, Color.Yellow); var range = target.Actor.Info.TraitInfo().Range; - self.QueueActivity(new AttackMoveActivity(self, move.MoveFollow(self, target, WDist.Zero, range, targetLineColor: Color.Yellow))); + self.QueueActivity(new AttackMoveActivity(self, () => move.MoveFollow(self, target, WDist.Zero, range, targetLineColor: Color.Yellow))); } public string VoicePhraseForOrder(Actor self, Order order) diff --git a/OpenRA.Mods.Common/Traits/Production.cs b/OpenRA.Mods.Common/Traits/Production.cs index cda6242d56..bae019d68b 100644 --- a/OpenRA.Mods.Common/Traits/Production.cs +++ b/OpenRA.Mods.Common/Traits/Production.cs @@ -90,8 +90,7 @@ namespace OpenRA.Mods.Common.Traits newUnit.QueueActivity(new Wait(exitinfo.ExitDelay, false)); newUnit.QueueActivity(move.MoveIntoWorld(newUnit, exit)); - newUnit.QueueActivity(new AttackMoveActivity( - newUnit, move.MoveTo(exitLocation, 1))); + newUnit.QueueActivity(new AttackMoveActivity(newUnit, () => move.MoveTo(exitLocation, 1))); } } diff --git a/OpenRA.Mods.Common/Traits/ProductionParadrop.cs b/OpenRA.Mods.Common/Traits/ProductionParadrop.cs index e61d79e810..8adcab4608 100644 --- a/OpenRA.Mods.Common/Traits/ProductionParadrop.cs +++ b/OpenRA.Mods.Common/Traits/ProductionParadrop.cs @@ -144,7 +144,7 @@ namespace OpenRA.Mods.Common.Traits newUnit.QueueActivity(new Wait(exitinfo.ExitDelay, false)); newUnit.QueueActivity(move.MoveIntoWorld(newUnit, exit)); - newUnit.QueueActivity(new AttackMoveActivity(newUnit, move.MoveTo(exitLocation, 1))); + newUnit.QueueActivity(new AttackMoveActivity(newUnit, () => move.MoveTo(exitLocation, 1))); } }