diff --git a/OpenRA.Mods.Common/Activities/Demolish.cs b/OpenRA.Mods.Common/Activities/Demolish.cs index 9b785ec116..66fb4c8822 100644 --- a/OpenRA.Mods.Common/Activities/Demolish.cs +++ b/OpenRA.Mods.Common/Activities/Demolish.cs @@ -9,55 +9,79 @@ */ #endregion +using System; using System.Drawing; using System.Linq; using OpenRA.Mods.Common.Effects; using OpenRA.Mods.Common.Traits; +using OpenRA.Traits; namespace OpenRA.Mods.Common.Activities { - class Demolish : LegacyEnter + class Demolish : Enter { - readonly Actor target; - readonly IDemolishable[] demolishables; readonly int delay; readonly int flashes; readonly int flashesDelay; readonly int flashInterval; readonly INotifyDemolition[] notifiers; + readonly EnterBehaviour enterBehaviour; - public Demolish(Actor self, Actor target, EnterBehaviour enterBehaviour, int delay, + Actor enterActor; + IDemolishable[] enterDemolishables; + + public Demolish(Actor self, Target target, EnterBehaviour enterBehaviour, int delay, int flashes, int flashesDelay, int flashInterval) - : base(self, target, enterBehaviour, targetLineColor: Color.Red) + : base(self, target, Color.Red) { - this.target = target; - demolishables = target.TraitsImplementing().ToArray(); notifiers = self.TraitsImplementing().ToArray(); this.delay = delay; this.flashes = flashes; this.flashesDelay = flashesDelay; this.flashInterval = flashInterval; + this.enterBehaviour = enterBehaviour; } - protected override bool CanReserve(Actor self) + protected override bool TryStartEnter(Actor self, Actor targetActor) { - return demolishables.Any(i => i.IsValidTarget(target, self)); + enterActor = targetActor; + enterDemolishables = targetActor.TraitsImplementing().ToArray(); + + // Make sure we can still demolish the target before entering + // (but not before, because this may stop the actor in the middle of nowhere) + if (!enterDemolishables.Any(i => i.IsValidTarget(enterActor, self))) + { + Cancel(self, true); + return false; + } + + return true; } - protected override void OnInside(Actor self) + protected override void OnEnterComplete(Actor self, Actor targetActor) { self.World.AddFrameEndTask(w => { - if (target.IsDead) + // Make sure the target hasn't changed while entering + // OnEnterComplete is only called if targetActor is alive + if (targetActor != enterActor) return; - w.Add(new FlashTarget(target, count: flashes, delay: flashesDelay, interval: flashInterval)); + if (!enterDemolishables.Any(i => i.IsValidTarget(enterActor, self))) + return; + + w.Add(new FlashTarget(enterActor, count: flashes, delay: flashesDelay, interval: flashInterval)); foreach (var ind in notifiers) ind.Demolishing(self); - foreach (var d in demolishables) - d.Demolish(target, self, delay); + foreach (var d in enterDemolishables) + d.Demolish(enterActor, self, delay); + + if (enterBehaviour == EnterBehaviour.Dispose) + self.Dispose(); + else if (enterBehaviour == EnterBehaviour.Suicide) + self.Kill(self); }); } } diff --git a/OpenRA.Mods.Common/Scripting/Properties/DemolitionProperties.cs b/OpenRA.Mods.Common/Scripting/Properties/DemolitionProperties.cs index 903a605ee1..a1ef82165c 100644 --- a/OpenRA.Mods.Common/Scripting/Properties/DemolitionProperties.cs +++ b/OpenRA.Mods.Common/Scripting/Properties/DemolitionProperties.cs @@ -31,7 +31,7 @@ namespace OpenRA.Mods.Common.Scripting [Desc("Demolish the target actor.")] public void Demolish(Actor target) { - Self.QueueActivity(new Demolish(Self, target, info.EnterBehaviour, info.DetonationDelay, + Self.QueueActivity(new Demolish(Self, Target.FromActor(target), info.EnterBehaviour, info.DetonationDelay, info.Flashes, info.FlashesDelay, info.FlashInterval)); } } diff --git a/OpenRA.Mods.Common/Traits/Demolition.cs b/OpenRA.Mods.Common/Traits/Demolition.cs index faafad13e9..dc1f0804f1 100644 --- a/OpenRA.Mods.Common/Traits/Demolition.cs +++ b/OpenRA.Mods.Common/Traits/Demolition.cs @@ -75,19 +75,18 @@ namespace OpenRA.Mods.Common.Traits if (order.OrderString != "C4") return; - var target = self.ResolveFrozenActorOrder(order, Color.Red); - if (target.Type != TargetType.Actor) - return; - - var demolishable = target.Actor.TraitOrDefault(); - if (demolishable == null || !demolishable.IsValidTarget(target.Actor, self)) - return; + if (order.Target.Type == TargetType.Actor) + { + var demolishables = order.Target.Actor.TraitsImplementing(); + if (!demolishables.Any(i => i.IsValidTarget(order.Target.Actor, self))) + return; + } if (!order.Queued) self.CancelActivity(); - self.SetTargetLine(target, Color.Red); - self.QueueActivity(new Demolish(self, target.Actor, info.EnterBehaviour, info.DetonationDelay, + self.SetTargetLine(order.Target, Color.Red); + self.QueueActivity(new Demolish(self, order.Target, info.EnterBehaviour, info.DetonationDelay, info.Flashes, info.FlashesDelay, info.FlashInterval)); }