diff --git a/OpenRA.Game/Support/ConditionExpression.cs b/OpenRA.Game/Support/ConditionExpression.cs index 984b5c4ee9..bf406ead9c 100644 --- a/OpenRA.Game/Support/ConditionExpression.cs +++ b/OpenRA.Game/Support/ConditionExpression.cs @@ -222,21 +222,21 @@ namespace OpenRA.Support return new VariableToken(start, expression.Substring(start)); } - static bool ParseSymbol(VariableToken t, IReadOnlyDictionary symbols) + static int ParseSymbol(VariableToken t, IReadOnlyDictionary symbols) { - bool value; + int value; symbols.TryGetValue(t.Symbol, out value); return value; } - static void ApplyBinaryOperation(Stack s, Func f) + static void ApplyBinaryOperation(Stack s, Func f) { var x = s.Pop(); var y = s.Pop(); s.Push(f(x, y)); } - static void ApplyUnaryOperation(Stack s, Func f) + static void ApplyUnaryOperation(Stack s, Func f) { var x = s.Pop(); s.Push(f(x)); @@ -271,21 +271,21 @@ namespace OpenRA.Support yield return s.Pop(); } - public bool Evaluate(IReadOnlyDictionary symbols) + public int Evaluate(IReadOnlyDictionary symbols) { - var s = new Stack(); + var s = new Stack(); foreach (var t in postfix) { if (t is AndToken) - ApplyBinaryOperation(s, (x, y) => y & x); + ApplyBinaryOperation(s, (x, y) => y > 0 ? x : y); else if (t is NotEqualsToken) - ApplyBinaryOperation(s, (x, y) => y ^ x); + ApplyBinaryOperation(s, (x, y) => (y != x) ? 1 : 0); else if (t is OrToken) - ApplyBinaryOperation(s, (x, y) => y | x); + ApplyBinaryOperation(s, (x, y) => y > 0 ? y : x); else if (t is EqualsToken) - ApplyBinaryOperation(s, (x, y) => y == x); + ApplyBinaryOperation(s, (x, y) => (y == x) ? 1 : 0); else if (t is NotToken) - ApplyUnaryOperation(s, x => !x); + ApplyUnaryOperation(s, x => (x > 0) ? 0 : 1); else if (t is VariableToken) s.Push(ParseSymbol((VariableToken)t, symbols)); } diff --git a/OpenRA.Mods.Common/Traits/Conditions/ConditionManager.cs b/OpenRA.Mods.Common/Traits/Conditions/ConditionManager.cs index b70f5460ae..d626c183c8 100644 --- a/OpenRA.Mods.Common/Traits/Conditions/ConditionManager.cs +++ b/OpenRA.Mods.Common/Traits/Conditions/ConditionManager.cs @@ -72,15 +72,15 @@ namespace OpenRA.Mods.Common.Traits int nextToken = 1; /// Cache of condition -> enabled state for quick evaluation of boolean conditions. - readonly Dictionary conditionCache = new Dictionary(); + readonly Dictionary conditionCache = new Dictionary(); /// Read-only version of conditionCache that is passed to IConditionConsumers. - IReadOnlyDictionary readOnlyConditionCache; + IReadOnlyDictionary readOnlyConditionCache; void INotifyCreated.Created(Actor self) { state = new Dictionary(); - readOnlyConditionCache = new ReadOnlyDictionary(conditionCache); + readOnlyConditionCache = new ReadOnlyDictionary(conditionCache); var allConsumers = new HashSet(); var allWatchers = self.TraitsImplementing().ToList(); @@ -96,7 +96,7 @@ namespace OpenRA.Mods.Common.Traits if (w.Condition == condition) cs.Watchers.Add(w); - conditionCache[condition] = false; + conditionCache[condition] = 0; } } @@ -108,7 +108,7 @@ namespace OpenRA.Mods.Common.Traits continue; conditionState.Tokens.Add(kv.Key); - conditionCache[kv.Value] = conditionState.Tokens.Count > 0; + conditionCache[kv.Value] = conditionState.Tokens.Count; } foreach (var sc in self.Info.TraitInfos()) @@ -133,7 +133,7 @@ namespace OpenRA.Mods.Common.Traits else conditionState.Tokens.Add(token); - conditionCache[condition] = conditionState.Tokens.Count > 0; + conditionCache[condition] = conditionState.Tokens.Count; foreach (var t in conditionState.Consumers) t.ConditionsChanged(self, readOnlyConditionCache); diff --git a/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs b/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs index c2315f99b4..3f197345b0 100644 --- a/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs +++ b/OpenRA.Mods.Common/Traits/Conditions/ConditionalTrait.cs @@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Traits /// Use as base class for *Info to subclass of UpgradableTrait. (See UpgradableTrait.) public abstract class ConditionalTraitInfo : IConditionConsumerInfo, IRulesetLoaded { - static readonly IReadOnlyDictionary NoConditions = new ReadOnlyDictionary(new Dictionary()); + static readonly IReadOnlyDictionary NoConditions = new ReadOnlyDictionary(new Dictionary()); [ConsumedConditionReference] [Desc("Boolean expression defining the condition to enable this trait.")] @@ -34,7 +34,7 @@ namespace OpenRA.Mods.Common.Traits public virtual void RulesetLoaded(Ruleset rules, ActorInfo ai) { - EnabledByDefault = RequiresCondition != null ? RequiresCondition.Evaluate(NoConditions) : true; + EnabledByDefault = RequiresCondition != null ? RequiresCondition.Evaluate(NoConditions) > 0 : true; } } @@ -77,13 +77,13 @@ namespace OpenRA.Mods.Common.Traits void INotifyCreated.Created(Actor self) { Created(self); } - void IConditionConsumer.ConditionsChanged(Actor self, IReadOnlyDictionary conditions) + void IConditionConsumer.ConditionsChanged(Actor self, IReadOnlyDictionary conditions) { if (Info.RequiresCondition == null) return; var wasDisabled = IsTraitDisabled; - IsTraitDisabled = !Info.RequiresCondition.Evaluate(conditions); + IsTraitDisabled = Info.RequiresCondition.Evaluate(conditions) <= 0; if (IsTraitDisabled != wasDisabled) { diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index 14cc4bfb93..175dedf20c 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -110,7 +110,7 @@ namespace OpenRA.Mods.Common.Traits public interface IConditionConsumer { IEnumerable Conditions { get; } - void ConditionsChanged(Actor self, IReadOnlyDictionary conditions); + void ConditionsChanged(Actor self, IReadOnlyDictionary conditions); } public interface INotifyHarvesterAction diff --git a/OpenRA.Test/OpenRA.Game/ConditionExpressionTest.cs b/OpenRA.Test/OpenRA.Game/ConditionExpressionTest.cs index c3063c07b2..3dccfb5489 100644 --- a/OpenRA.Test/OpenRA.Game/ConditionExpressionTest.cs +++ b/OpenRA.Test/OpenRA.Game/ConditionExpressionTest.cs @@ -21,20 +21,20 @@ namespace OpenRA.Test [TestFixture] public class ConditionExpressionTest { - IReadOnlyDictionary testValues = new ReadOnlyDictionary(new Dictionary() + IReadOnlyDictionary testValues = new ReadOnlyDictionary(new Dictionary() { - { "true", true }, - { "false", false } + { "true", 1 }, + { "false", 0 } }); void AssertFalse(string expression) { - Assert.False(new ConditionExpression(expression).Evaluate(testValues), expression); + Assert.False(new ConditionExpression(expression).Evaluate(testValues) > 0, expression); } void AssertTrue(string expression) { - Assert.True(new ConditionExpression(expression).Evaluate(testValues), expression); + Assert.True(new ConditionExpression(expression).Evaluate(testValues) > 0, expression); } void AssertParseFailure(string expression) @@ -69,7 +69,7 @@ namespace OpenRA.Test AssertFalse("false == true"); } - [TestCase(TestName = "Not-equals (XOR) operation")] + [TestCase(TestName = "Not-equals operation")] public void TestNotEquals() { AssertFalse("true != true"); @@ -141,7 +141,7 @@ namespace OpenRA.Test AssertParseFailure("false ||"); } - [TestCase(TestName = "Undefined symbols are treated as `false` values")] + [TestCase(TestName = "Undefined symbols are treated as `false` (0) values")] public void TestUndefinedSymbols() { AssertFalse("undef1 || undef2");