diff --git a/OpenRA.Mods.Common/Traits/Upgrades/UpgradableTrait.cs b/OpenRA.Mods.Common/Traits/Upgrades/UpgradableTrait.cs index 584586a56b..086c960daf 100644 --- a/OpenRA.Mods.Common/Traits/Upgrades/UpgradableTrait.cs +++ b/OpenRA.Mods.Common/Traits/Upgrades/UpgradableTrait.cs @@ -19,6 +19,13 @@ namespace OpenRA.Mods.Common.Traits /// Use as base class for *Info to subclass of UpgradableTrait. (See UpgradableTrait.) public abstract class UpgradableTraitInfo : IUpgradableInfo, IRulesetLoaded { + static readonly Dictionary NoConditions = new Dictionary(); + + [UpgradeUsedReference] + [Desc("Boolean expression defining the condition to enable this trait.", + "Overrides UpgradeTypes/UpgradeMinEnabledLevel/UpgradeMaxEnabledLevel/UpgradeMaxAcceptedLevel if set.")] + public readonly BooleanExpression RequiresCondition = null; + [UpgradeUsedReference] [Desc("The upgrade types which can enable or disable this trait.")] public readonly HashSet UpgradeTypes = new HashSet(); @@ -44,7 +51,8 @@ namespace OpenRA.Mods.Common.Traits public virtual void RulesetLoaded(Ruleset rules, ActorInfo ai) { - EnabledByDefault = UpgradeMinEnabledLevel < 1; + EnabledByDefault = RequiresCondition != null ? + RequiresCondition.Evaluate(NoConditions) : UpgradeMinEnabledLevel < 1; } } @@ -56,33 +64,63 @@ namespace OpenRA.Mods.Common.Traits public abstract class UpgradableTrait : IUpgradable, IDisabledTrait, ISync where InfoType : UpgradableTraitInfo { public readonly InfoType Info; - public IEnumerable UpgradeTypes { get { return Info.UpgradeTypes; } } + readonly Dictionary conditions = new Dictionary(); + + IEnumerable IUpgradable.UpgradeTypes + { + get + { + if (Info.RequiresCondition != null) + return Info.RequiresCondition.Variables; + + return Info.UpgradeTypes; + } + } + [Sync] public bool IsTraitDisabled { get; private set; } public UpgradableTrait(InfoType info) { Info = info; - IsTraitDisabled = info.UpgradeTypes != null && info.UpgradeTypes.Count > 0 && info.UpgradeMinEnabledLevel > 0; + + // TODO: Set initial state from a ConditionsInit once that exists + if (info.RequiresCondition != null) + IsTraitDisabled = !info.RequiresCondition.Evaluate(conditions); + else + IsTraitDisabled = info.UpgradeTypes != null && info.UpgradeTypes.Count > 0 && info.UpgradeMinEnabledLevel > 0; } - public bool AcceptsUpgradeLevel(Actor self, string type, int level) + bool IUpgradable.AcceptsUpgradeLevel(Actor self, string type, int level) { + if (Info.RequiresCondition != null) + return level == 1; + return level > 0 && level <= Info.UpgradeMaxAcceptedLevel; } - public void UpgradeLevelChanged(Actor self, string type, int oldLevel, int newLevel) + void IUpgradable.UpgradeLevelChanged(Actor self, string type, int oldLevel, int newLevel) { - if (!Info.UpgradeTypes.Contains(type)) - return; - - // Restrict the levels to the allowed range - oldLevel = oldLevel.Clamp(0, Info.UpgradeMaxAcceptedLevel); - newLevel = newLevel.Clamp(0, Info.UpgradeMaxAcceptedLevel); - if (oldLevel == newLevel) - return; - var wasDisabled = IsTraitDisabled; - IsTraitDisabled = newLevel < Info.UpgradeMinEnabledLevel || newLevel > Info.UpgradeMaxEnabledLevel; + + if (Info.RequiresCondition != null) + { + conditions[type] = newLevel > 0; + IsTraitDisabled = !Info.RequiresCondition.Evaluate(conditions); + } + else + { + if (!Info.UpgradeTypes.Contains(type)) + return; + + // Restrict the levels to the allowed range + oldLevel = oldLevel.Clamp(0, Info.UpgradeMaxAcceptedLevel); + newLevel = newLevel.Clamp(0, Info.UpgradeMaxAcceptedLevel); + if (oldLevel == newLevel) + return; + + IsTraitDisabled = newLevel < Info.UpgradeMinEnabledLevel || newLevel > Info.UpgradeMaxEnabledLevel; + } + UpgradeLevelChanged(self, oldLevel, newLevel); if (IsTraitDisabled != wasDisabled)