diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index 802806a1f9..fddf393d21 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -495,6 +495,7 @@
+
diff --git a/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs b/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs
index dc942ba0a6..46d4cf30dc 100644
--- a/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs
+++ b/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs
@@ -15,10 +15,10 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
- /// Use as base class for *Info to subclass of UpgradableTrait. (See UpgradableTrait.)
+ /// Use as base class for *Info to subclass of ConditionalTrait. (See ConditionalTrait.)
public abstract class ConditionalTraitInfo : IObservesVariablesInfo, IRulesetLoaded
{
- static readonly IReadOnlyDictionary NoConditions = new ReadOnlyDictionary(new Dictionary());
+ protected static readonly IReadOnlyDictionary NoConditions = new ReadOnlyDictionary(new Dictionary());
[ConsumedConditionReference]
[Desc("Boolean expression defining the condition to enable this trait.")]
@@ -39,7 +39,7 @@ namespace OpenRA.Mods.Common.Traits
///
/// Abstract base for enabling and disabling trait using conditions.
- /// Requires basing *Info on UpgradableTraitInfo and using base(info) constructor.
+ /// Requires basing *Info on ConditionalTraitInfo and using base(info) constructor.
/// TraitEnabled will be called at creation if the trait starts enabled or does not use conditions.
///
public abstract class ConditionalTrait : IObservesVariables, IDisabledTrait, INotifyCreated, ISync where InfoType : ConditionalTraitInfo
diff --git a/OpenRA.Mods.Common/Traits/Conditions/PausableConditionalTrait.cs b/OpenRA.Mods.Common/Traits/Conditions/PausableConditionalTrait.cs
new file mode 100644
index 0000000000..d6203e3a30
--- /dev/null
+++ b/OpenRA.Mods.Common/Traits/Conditions/PausableConditionalTrait.cs
@@ -0,0 +1,81 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2017 The OpenRA Developers (see AUTHORS)
+ * This file is part of OpenRA, which is free software. It is made
+ * available to you under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version. For more
+ * information, see COPYING.
+ */
+#endregion
+
+using System.Collections.Generic;
+using OpenRA.Primitives;
+using OpenRA.Support;
+using OpenRA.Traits;
+
+namespace OpenRA.Mods.Common.Traits
+{
+ /// Use as base class for *Info to subclass of PausableConditionalTrait. (See PausableConditionalTrait.)
+ public abstract class PausableConditionalTraitInfo : ConditionalTraitInfo
+ {
+ [ConsumedConditionReference]
+ [Desc("Boolean expression defining the condition to pause this trait.")]
+ public readonly BooleanExpression PauseOnCondition = null;
+
+ public bool PausedByDefault { get; private set; }
+
+ public override void RulesetLoaded(Ruleset rules, ActorInfo ai)
+ {
+ base.RulesetLoaded(rules, ai);
+ PausedByDefault = PauseOnCondition != null && PauseOnCondition.Evaluate(NoConditions);
+ }
+ }
+
+ ///
+ /// Abstract base for enabling and disabling trait using conditions.
+ /// Requires basing *Info on PausableConditionalTraitInfo and using base(info) constructor.
+ /// TraitResumed will be called at creation if the trait starts not paused or does not have a pause condition.
+ ///
+ public abstract class PausableConditionalTrait : ConditionalTrait where InfoType : PausableConditionalTraitInfo
+ {
+ [Sync] public bool IsTraitPaused { get; private set; }
+
+ protected PausableConditionalTrait(InfoType info) : base(info) { IsTraitPaused = info.PausedByDefault; }
+
+ protected override void Created(Actor self)
+ {
+ base.Created(self);
+ if (Info.PauseOnCondition == null)
+ TraitResumed(self);
+ }
+
+ // Overrides must call `base.GetVariableObservers()` to avoid breaking RequiresCondition or PauseOnCondition.
+ public override IEnumerable GetVariableObservers()
+ {
+ foreach (var observer in base.GetVariableObservers())
+ yield return observer;
+
+ if (Info.PauseOnCondition != null)
+ yield return new VariableObserver(PauseConditionsChanged, Info.PauseOnCondition.Variables);
+ }
+
+ void PauseConditionsChanged(Actor self, IReadOnlyDictionary conditions)
+ {
+ var wasPaused = IsTraitPaused;
+ IsTraitPaused = Info.PauseOnCondition.Evaluate(conditions);
+
+ if (IsTraitPaused != wasPaused)
+ {
+ if (wasPaused)
+ TraitResumed(self);
+ else
+ TraitPaused(self);
+ }
+ }
+
+ // Subclasses can add pause support by querying IsTraitPaused and/or overriding these methods.
+ protected virtual void TraitResumed(Actor self) { }
+ protected virtual void TraitPaused(Actor self) { }
+ }
+}