diff --git a/OpenRA.Mods.Cnc/Activities/Infiltrate.cs b/OpenRA.Mods.Cnc/Activities/Infiltrate.cs index d991fa643a..08dbde6161 100644 --- a/OpenRA.Mods.Cnc/Activities/Infiltrate.cs +++ b/OpenRA.Mods.Cnc/Activities/Infiltrate.cs @@ -9,9 +9,9 @@ */ #endregion +using System; using System.Drawing; using System.Linq; -using OpenRA.Activities; using OpenRA.Mods.Cnc.Traits; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Traits; @@ -19,34 +19,51 @@ using OpenRA.Traits; namespace OpenRA.Mods.Cnc.Activities { - class Infiltrate : LegacyEnter + class Infiltrate : Enter { - readonly Actor target; readonly Infiltrates infiltrates; readonly INotifyInfiltration[] notifiers; + Actor enterActor; - public Infiltrate(Actor self, Actor target, Infiltrates infiltrate) - : base(self, target, infiltrate.Info.EnterBehaviour, targetLineColor: Color.Red) + public Infiltrate(Actor self, Target target, Infiltrates infiltrates) + : base(self, target, Color.Red) { - this.target = target; - infiltrates = infiltrate; + this.infiltrates = infiltrates; notifiers = self.TraitsImplementing().ToArray(); } - protected override void OnInside(Actor self) + protected override void TickInner(Actor self, Target target, bool targetIsDeadOrHiddenActor) { - if (target.IsDead) - return; + if (infiltrates.IsTraitDisabled) + Cancel(self, true); + } - var stance = self.Owner.Stances[target.Owner]; - if (!infiltrates.Info.ValidStances.HasStance(stance)) + protected override bool TryStartEnter(Actor self, Actor targetActor) + { + // 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 (!infiltrates.CanInfiltrateTarget(self, Target.FromActor(targetActor))) + { + Cancel(self, true); + return false; + } + + enterActor = targetActor; + return true; + } + + protected override void OnEnterComplete(Actor self, Actor targetActor) + { + // Make sure the target hasn't changed while entering + // OnEnterComplete is only called if targetActor is alive + if (targetActor != enterActor || !infiltrates.CanInfiltrateTarget(self, Target.FromActor(targetActor))) return; foreach (var ini in notifiers) ini.Infiltrating(self); - foreach (var t in target.TraitsImplementing()) - t.Infiltrated(target, self, infiltrates.Info.Types); + foreach (var t in targetActor.TraitsImplementing()) + t.Infiltrated(targetActor, self, infiltrates.Info.Types); var exp = self.Owner.PlayerActor.TraitOrDefault(); if (exp != null) @@ -55,14 +72,11 @@ namespace OpenRA.Mods.Cnc.Activities if (!string.IsNullOrEmpty(infiltrates.Info.Notification)) Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", infiltrates.Info.Notification, self.Owner.Faction.InternalName); - } - public override Activity Tick(Actor self) - { - if (infiltrates.IsTraitDisabled) - Cancel(self); - - return base.Tick(self); + if (infiltrates.Info.EnterBehaviour == EnterBehaviour.Dispose) + self.Dispose(); + else if (infiltrates.Info.EnterBehaviour == EnterBehaviour.Suicide) + self.Kill(self); } } } diff --git a/OpenRA.Mods.Cnc/Scripting/Properties/InfiltrateProperties.cs b/OpenRA.Mods.Cnc/Scripting/Properties/InfiltrateProperties.cs index c50b82b006..994e70b543 100644 --- a/OpenRA.Mods.Cnc/Scripting/Properties/InfiltrateProperties.cs +++ b/OpenRA.Mods.Cnc/Scripting/Properties/InfiltrateProperties.cs @@ -37,7 +37,7 @@ namespace OpenRA.Mods.Cnc.Scripting if (infiltrates == null) throw new LuaException("{0} tried to infiltrate invalid target {1}!".F(Self, target)); - Self.QueueActivity(new Infiltrate(Self, target, infiltrates)); + Self.QueueActivity(new Infiltrate(Self, Target.FromActor(target), infiltrates)); } } } diff --git a/OpenRA.Mods.Cnc/Traits/Infiltration/Infiltrates.cs b/OpenRA.Mods.Cnc/Traits/Infiltration/Infiltrates.cs index 1a5c10742c..6339ef04ba 100644 --- a/OpenRA.Mods.Cnc/Traits/Infiltration/Infiltrates.cs +++ b/OpenRA.Mods.Cnc/Traits/Infiltration/Infiltrates.cs @@ -92,21 +92,34 @@ namespace OpenRA.Mods.Cnc.Traits ? Info.Voice : null; } + public bool CanInfiltrateTarget(Actor self, Target target) + { + switch (target.Type) + { + case TargetType.Actor: + return Info.Types.Overlaps(target.Actor.GetEnabledTargetTypes()) && + Info.ValidStances.HasStance(self.Owner.Stances[target.Actor.Owner]); + case TargetType.FrozenActor: + return target.FrozenActor.IsValid && Info.Types.Overlaps(target.FrozenActor.TargetTypes) && + Info.ValidStances.HasStance(self.Owner.Stances[target.FrozenActor.Owner]); + default: + return false; + } + } + public void ResolveOrder(Actor self, Order order) { if (order.OrderString != "Infiltrate" || !IsValidOrder(self, order) || IsTraitDisabled) return; - var target = self.ResolveFrozenActorOrder(order, Color.Red); - if (target.Type != TargetType.Actor - || !Info.Types.Overlaps(target.Actor.GetAllTargetTypes())) + if (!CanInfiltrateTarget(self, order.Target)) return; if (!order.Queued) self.CancelActivity(); - self.SetTargetLine(target, Color.Red); - self.QueueActivity(new Infiltrate(self, target.Actor, this)); + self.SetTargetLine(order.Target, Color.Red); + self.QueueActivity(new Infiltrate(self, order.Target, this)); } }