diff --git a/OpenRA.Game/Activities/Activity.cs b/OpenRA.Game/Activities/Activity.cs index 97b7708c1e..45fbf91f38 100644 --- a/OpenRA.Game/Activities/Activity.cs +++ b/OpenRA.Game/Activities/Activity.cs @@ -201,7 +201,7 @@ namespace OpenRA.Activities /// protected virtual void OnLastRun(Actor self) { } - public virtual bool Cancel(Actor self) + public virtual bool Cancel(Actor self, bool keepQueue = false) { if (!IsInterruptible) return false; @@ -209,9 +209,11 @@ namespace OpenRA.Activities if (ChildActivity != null && !ChildActivity.Cancel(self)) return false; - State = ActivityState.Canceled; - NextActivity = null; + if (!keepQueue) + NextActivity = null; + ChildActivity = null; + State = ActivityState.Canceled; return true; } diff --git a/OpenRA.Mods.Common/Activities/DeliverUnit.cs b/OpenRA.Mods.Common/Activities/DeliverUnit.cs index 97b4b24d06..ba38ec32c5 100644 --- a/OpenRA.Mods.Common/Activities/DeliverUnit.cs +++ b/OpenRA.Mods.Common/Activities/DeliverUnit.cs @@ -207,7 +207,7 @@ namespace OpenRA.Mods.Common.Activities }); } - public override bool Cancel(Actor self) + public override bool Cancel(Actor self, bool keepQueue = false) { if (!IsCanceled && innerActivity != null && !innerActivity.Cancel(self)) return false; diff --git a/OpenRA.Mods.Common/Activities/Enter.cs b/OpenRA.Mods.Common/Activities/Enter.cs index 5a095e757b..34894fe5c9 100644 --- a/OpenRA.Mods.Common/Activities/Enter.cs +++ b/OpenRA.Mods.Common/Activities/Enter.cs @@ -112,7 +112,7 @@ namespace OpenRA.Mods.Common.Activities inner.Cancel(self); } - public override bool Cancel(Actor self) + public override bool Cancel(Actor self, bool keepQueue = false) { AbortOrExit(self); if (nextState < EnterState.Exiting) diff --git a/OpenRA.Mods.Common/Activities/HarvesterDockSequence.cs b/OpenRA.Mods.Common/Activities/HarvesterDockSequence.cs index 5a7e61e8d4..183fcd1ea5 100644 --- a/OpenRA.Mods.Common/Activities/HarvesterDockSequence.cs +++ b/OpenRA.Mods.Common/Activities/HarvesterDockSequence.cs @@ -81,7 +81,7 @@ namespace OpenRA.Mods.Common.Activities throw new InvalidOperationException("Invalid harvester dock state"); } - public override bool Cancel(Actor self) + public override bool Cancel(Actor self, bool keepQueue = false) { dockingState = DockingState.Undock; return base.Cancel(self); diff --git a/OpenRA.Mods.Common/Activities/Move/AttackMoveActivity.cs b/OpenRA.Mods.Common/Activities/Move/AttackMoveActivity.cs index 4a34348177..6e8c29b9e5 100644 --- a/OpenRA.Mods.Common/Activities/Move/AttackMoveActivity.cs +++ b/OpenRA.Mods.Common/Activities/Move/AttackMoveActivity.cs @@ -46,12 +46,12 @@ namespace OpenRA.Mods.Common.Activities return this; } - public override bool Cancel(Actor self) + public override bool Cancel(Actor self, bool keepQueue = false) { if (!IsCanceled && inner != null && !inner.Cancel(self)) return false; - return base.Cancel(self); + return base.Cancel(self, keepQueue); } public override IEnumerable GetTargets(Actor self) diff --git a/OpenRA.Mods.Common/Activities/Move/Move.cs b/OpenRA.Mods.Common/Activities/Move/Move.cs index eebf40fae8..6d728670c5 100644 --- a/OpenRA.Mods.Common/Activities/Move/Move.cs +++ b/OpenRA.Mods.Common/Activities/Move/Move.cs @@ -334,9 +334,9 @@ namespace OpenRA.Mods.Common.Activities } } - public override bool Cancel(Actor self) + public override bool Cancel(Actor self, bool keepQueue = false) { - Move.Cancel(self); + Move.Cancel(self, keepQueue); return base.Cancel(self); } diff --git a/OpenRA.Mods.Common/Activities/Move/MoveAdjacentTo.cs b/OpenRA.Mods.Common/Activities/Move/MoveAdjacentTo.cs index e2c9a81215..3c6028119f 100644 --- a/OpenRA.Mods.Common/Activities/Move/MoveAdjacentTo.cs +++ b/OpenRA.Mods.Common/Activities/Move/MoveAdjacentTo.cs @@ -161,7 +161,7 @@ namespace OpenRA.Mods.Common.Activities return Target.None; } - public override bool Cancel(Actor self) + public override bool Cancel(Actor self, bool keepQueue = false) { if (!IsCanceled && inner != null && !inner.Cancel(self)) return false; diff --git a/OpenRA.Mods.Common/Activities/PickupUnit.cs b/OpenRA.Mods.Common/Activities/PickupUnit.cs index c27d840e57..ec98f8a55d 100644 --- a/OpenRA.Mods.Common/Activities/PickupUnit.cs +++ b/OpenRA.Mods.Common/Activities/PickupUnit.cs @@ -157,12 +157,12 @@ namespace OpenRA.Mods.Common.Activities }); } - public override bool Cancel(Actor self) + public override bool Cancel(Actor self, bool keepQueue = false) { if (!IsCanceled && innerActivity != null && !innerActivity.Cancel(self)) return false; - return base.Cancel(self); + return base.Cancel(self, keepQueue); } } } diff --git a/OpenRA.Mods.Common/Activities/Transform.cs b/OpenRA.Mods.Common/Activities/Transform.cs index 3cfd3d683e..f5eaf34e02 100644 --- a/OpenRA.Mods.Common/Activities/Transform.cs +++ b/OpenRA.Mods.Common/Activities/Transform.cs @@ -12,7 +12,9 @@ using System.Linq; using OpenRA.Activities; using OpenRA.Mods.Common.Traits; +using OpenRA.Mods.Common.Traits.Render; using OpenRA.Primitives; +using OpenRA.Traits; namespace OpenRA.Mods.Common.Activities { @@ -32,11 +34,61 @@ namespace OpenRA.Mods.Common.Activities ToActor = toActor; } + protected override void OnFirstRun(Actor self) + { + if (self.Info.HasTraitInfo()) + QueueChild(new Turn(self, Facing)); + + if (self.Info.HasTraitInfo()) + QueueChild(new HeliLand(self, true)); + } + public override Activity Tick(Actor self) { if (IsCanceled) return NextActivity; + if (ChildActivity != null) + { + ActivityUtils.RunActivity(self, ChildActivity); + return this; + } + + // Prevent deployment in bogus locations + var transforms = self.TraitOrDefault(); + var building = self.TraitOrDefault(); + if ((transforms != null && !transforms.CanDeploy()) || (building != null && !building.Lock())) + { + Cancel(self, true); + return NextActivity; + } + + foreach (var nt in self.TraitsImplementing()) + nt.BeforeTransform(self); + + var makeAnimation = self.TraitOrDefault(); + if (makeAnimation != null) + { + // Once the make animation starts the activity must not be stopped anymore. + IsInterruptible = false; + + // Wait forever + QueueChild(new WaitFor(() => false)); + makeAnimation.Reverse(self, () => DoTransform(self)); + return this; + } + + return NextActivity; + } + + protected override void OnLastRun(Actor self) + { + if (!IsCanceled) + DoTransform(self); + } + + void DoTransform(Actor self) + { self.World.AddFrameEndTask(w => { if (self.IsDead) @@ -84,11 +136,10 @@ namespace OpenRA.Mods.Common.Activities if (selected) w.Selection.Add(w, a); + if (controlgroup.HasValue) w.Selection.AddToControlGroup(a, controlgroup.Value); }); - - return this; } } } diff --git a/OpenRA.Mods.Common/Activities/Wait.cs b/OpenRA.Mods.Common/Activities/Wait.cs index f9f11697b2..66e3f68d07 100644 --- a/OpenRA.Mods.Common/Activities/Wait.cs +++ b/OpenRA.Mods.Common/Activities/Wait.cs @@ -30,9 +30,9 @@ namespace OpenRA.Mods.Common.Activities return (remainingTicks-- == 0) ? NextActivity : this; } - public override bool Cancel(Actor self) + public override bool Cancel(Actor self, bool keepQueue = false) { - if (!base.Cancel(self)) + if (!base.Cancel(self, keepQueue)) return false; remainingTicks = 0; @@ -56,9 +56,9 @@ namespace OpenRA.Mods.Common.Activities return (f == null || f()) ? NextActivity : this; } - public override bool Cancel(Actor self) + public override bool Cancel(Actor self, bool keepQueue = false) { - if (!base.Cancel(self)) + if (!base.Cancel(self, keepQueue)) return false; f = null; diff --git a/OpenRA.Mods.Common/Activities/WaitForTransport.cs b/OpenRA.Mods.Common/Activities/WaitForTransport.cs index 6c5d30e716..0ecd037397 100644 --- a/OpenRA.Mods.Common/Activities/WaitForTransport.cs +++ b/OpenRA.Mods.Common/Activities/WaitForTransport.cs @@ -41,12 +41,12 @@ namespace OpenRA.Mods.Common.Activities return this; } - public override bool Cancel(Actor self) + public override bool Cancel(Actor self, bool keepQueue = false) { if (!IsCanceled && inner != null && !inner.Cancel(self)) return false; - return base.Cancel(self); + return base.Cancel(self, keepQueue); } } } diff --git a/OpenRA.Mods.Common/Scripting/CallLuaFunc.cs b/OpenRA.Mods.Common/Scripting/CallLuaFunc.cs index 272aa4a20e..660c8503e8 100644 --- a/OpenRA.Mods.Common/Scripting/CallLuaFunc.cs +++ b/OpenRA.Mods.Common/Scripting/CallLuaFunc.cs @@ -43,9 +43,9 @@ namespace OpenRA.Mods.Common.Activities return NextActivity; } - public override bool Cancel(Actor self) + public override bool Cancel(Actor self, bool keepQueue = false) { - if (!base.Cancel(self)) + if (!base.Cancel(self, keepQueue)) return false; Dispose(); diff --git a/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs b/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs index be03da03e6..dec70c2c5e 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs @@ -51,7 +51,7 @@ namespace OpenRA.Mods.Common.Traits.Render Forward(self, () => building.NotifyBuildingComplete(self)); } - void Forward(Actor self, Action onComplete) + public void Forward(Actor self, Action onComplete) { if (conditionManager != null && !string.IsNullOrEmpty(info.Condition) && token == ConditionManager.InvalidConditionToken) token = conditionManager.GrantCondition(self, info.Condition); @@ -66,7 +66,7 @@ namespace OpenRA.Mods.Common.Traits.Render }); } - void Reverse(Actor self, Action onComplete) + public void Reverse(Actor self, Action onComplete) { if (conditionManager != null && !string.IsNullOrEmpty(info.Condition) && token == ConditionManager.InvalidConditionToken) token = conditionManager.GrantCondition(self, info.Condition); diff --git a/OpenRA.Mods.Common/Traits/Transforms.cs b/OpenRA.Mods.Common/Traits/Transforms.cs index da93479c40..dcb184143d 100644 --- a/OpenRA.Mods.Common/Traits/Transforms.cs +++ b/OpenRA.Mods.Common/Traits/Transforms.cs @@ -10,10 +10,8 @@ #endregion using System.Collections.Generic; -using OpenRA.Activities; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Orders; -using OpenRA.Mods.Common.Traits.Render; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits @@ -73,7 +71,7 @@ namespace OpenRA.Mods.Common.Traits return (order.OrderString == "DeployTransform") ? info.Voice : null; } - bool CanDeploy() + public bool CanDeploy() { var building = self.TraitOrDefault(); if (building != null && building.Locked) @@ -113,43 +111,14 @@ namespace OpenRA.Mods.Common.Traits if (!queued) self.CancelActivity(); - if (self.Info.HasTraitInfo()) - self.QueueActivity(new Turn(self, info.Facing)); - - if (self.Info.HasTraitInfo()) - self.QueueActivity(new HeliLand(self, true)); - - self.QueueActivity(new CallFunc(() => + self.QueueActivity(new Transform(self, info.IntoActor) { - // Prevent deployment in bogus locations - var building = self.TraitOrDefault(); - if (!CanDeploy() || (building != null && !building.Lock())) - return; - - foreach (var nt in self.TraitsImplementing()) - nt.BeforeTransform(self); - - var transform = new Transform(self, info.IntoActor) - { - Offset = info.Offset, - Facing = info.Facing, - Sounds = info.TransformSounds, - Notification = info.TransformNotification, - Faction = faction - }; - - // Try and stop the actor from doing anything between the sanity checks above - // and the actual transform, which we're about to queue. - // TODO: The proper way to do this is to write all the transform code as a nested activity. - if (self.CurrentActivity.NextInQueue != null) - self.CurrentActivity.NextInQueue.Cancel(self); - - var makeAnimation = self.TraitOrDefault(); - if (makeAnimation != null) - makeAnimation.Reverse(self, transform); - else - self.QueueActivity(transform); - })); + Offset = info.Offset, + Facing = info.Facing, + Sounds = info.TransformSounds, + Notification = info.TransformNotification, + Faction = faction + }); } public void ResolveOrder(Actor self, Order order)