diff --git a/OpenRA.Game/Activities/Activity.cs b/OpenRA.Game/Activities/Activity.cs index b0661577f2..cf610a18f0 100644 --- a/OpenRA.Game/Activities/Activity.cs +++ b/OpenRA.Game/Activities/Activity.cs @@ -171,6 +171,20 @@ namespace OpenRA.Activities act = act.childActivity; } } + + public IEnumerable ActivitiesImplementing() where T : IActivityInterface + { + if (childActivity != null) + foreach (var a in childActivity.ActivitiesImplementing()) + yield return a; + + if (this is T) + yield return (T)(object)this; + + if (NextActivity != null) + foreach (var a in NextActivity.ActivitiesImplementing()) + yield return a; + } } public static class ActivityExts diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index a17acda400..3c648c1ac1 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -350,6 +350,8 @@ namespace OpenRA.Traits [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1302:InterfaceNamesMustBeginWithI", Justification = "Not a real interface, but more like a tag.")] public interface Requires where T : class, ITraitInfoInterface { } + public interface IActivityInterface { } + [RequireExplicitImplementation] public interface INotifySelected { void Selected(Actor self); } [RequireExplicitImplementation] diff --git a/OpenRA.Mods.Common/Traits/AutoTarget.cs b/OpenRA.Mods.Common/Traits/AutoTarget.cs index 23ea3d34ef..0d3a07aa71 100644 --- a/OpenRA.Mods.Common/Traits/AutoTarget.cs +++ b/OpenRA.Mods.Common/Traits/AutoTarget.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Linq; +using OpenRA.Activities; using OpenRA.Primitives; using OpenRA.Traits; @@ -18,6 +19,18 @@ namespace OpenRA.Mods.Common.Traits { public enum UnitStance { HoldFire, ReturnFire, Defend, AttackAnything } + [RequireExplicitImplementation] + public interface IActivityNotifyStanceChanged : IActivityInterface + { + void StanceChanged(Actor self, AutoTarget autoTarget, UnitStance oldStance, UnitStance newStance); + } + + [RequireExplicitImplementation] + public interface INotifyStanceChanged + { + void StanceChanged(Actor self, AutoTarget autoTarget, UnitStance oldStance, UnitStance newStance); + } + [Desc("The actor will automatically engage the enemy when it is in range.")] public class AutoTargetInfo : ConditionalTraitInfo, Requires, IEditorActorOptions { @@ -126,6 +139,7 @@ namespace OpenRA.Mods.Common.Traits UnitStance stance; ConditionManager conditionManager; IDisableAutoTarget[] disableAutoTarget; + INotifyStanceChanged[] notifyStanceChanged; IEnumerable activeTargetPriorities; int conditionToken = ConditionManager.InvalidConditionToken; @@ -134,8 +148,16 @@ namespace OpenRA.Mods.Common.Traits if (stance == value) return; + var oldStance = stance; stance = value; ApplyStanceCondition(self); + + foreach (var nsc in notifyStanceChanged) + nsc.StanceChanged(self, this, oldStance, stance); + + if (self.CurrentActivity != null) + foreach (var a in self.CurrentActivity.ActivitiesImplementing()) + a.StanceChanged(self, this, oldStance, stance); } void ApplyStanceCondition(Actor self) @@ -176,6 +198,7 @@ namespace OpenRA.Mods.Common.Traits conditionManager = self.TraitOrDefault(); disableAutoTarget = self.TraitsImplementing().ToArray(); + notifyStanceChanged = self.TraitsImplementing().ToArray(); ApplyStanceCondition(self); }