public RequirementComparisonViewModel(Requirement requirement, Requirement compareRequirement, NumberFormat numberFormat, IDictionary <int, string> notes) : base(requirement, numberFormat, notes) { if (compareRequirement == null) { IsModified = true; } else { CompareRequirement = compareRequirement; UpdateOtherDefinition(numberFormat); if (requirement == null) { IsModified = true; } else if (requirement.HitCount != compareRequirement.HitCount) { // if the HitCounts differ, mark modified regardless of whether the evaluations are the same IsModified = true; } else if (!compareRequirement.Equals(requirement)) { // not identical. check to see if they evaluate to the same value var evaluation = requirement.Evaluate(); if (evaluation == null || compareRequirement.Evaluate() != evaluation) { IsModified = true; } } } }
private ParseErrorExpression ExecuteAchievementComparison(ComparisonExpression comparison, InterpreterScope scope) { var left = comparison.Left; var right = comparison.Right; if (left.Type == ExpressionType.Comparison || right.Type == ExpressionType.Comparison) { return(new ParseErrorExpression("comparison did not evaluate to a valid comparison", comparison)); } var context = scope.GetContext <TriggerBuilderContext>(); var op = GetRequirementOperator(comparison.Operation); var leftField = CreateFieldFromExpression(left); if (leftField.Type != FieldType.None) { var rightField = CreateFieldFromExpression(right); if (rightField.Type != FieldType.None) { // comparing two constants, convert to always_true or always_false var requirement = new Requirement { Left = leftField, Operator = op, Right = rightField, }; if (requirement.Evaluate() == true) { context.Trigger.Add(AlwaysTrueFunction.CreateAlwaysTrueRequirement()); } else { context.Trigger.Add(AlwaysFalseFunction.CreateAlwaysFalseRequirement()); } return(null); } // swap the operands and operator so the constant is on the right var temp = left; left = right; right = temp; op = Requirement.GetReversedRequirementOperator(op); } var error = ExecuteAchievementExpression(left, scope); if (error != null) { return(ParseErrorExpression.WrapError(error, "Invalid value", left)); } if (right.Type == ExpressionType.IntegerConstant || right.Type == ExpressionType.FloatConstant) { var lastRequirement = context.LastRequirement; if (lastRequirement.Operator != RequirementOperator.None) { // try to rearrange so the last requirement doesn't have a modifier for (int i = context.Trigger.Count - 2; i >= 0; --i) { var requirement = context.Trigger.ElementAt(i); if (requirement.Type == RequirementType.AddSource && requirement.Operator == RequirementOperator.None) { context.Trigger.Remove(lastRequirement); context.Trigger.Add(new Requirement { Left = requirement.Left }); requirement.Left = lastRequirement.Left; requirement.Operator = lastRequirement.Operator; requirement.Right = lastRequirement.Right; lastRequirement = context.LastRequirement; break; } if (requirement.Type != RequirementType.AddSource && requirement.Type != RequirementType.SubSource && requirement.Type != RequirementType.AddAddress) { break; } } if (lastRequirement.Operator != RequirementOperator.None) { // last requirement still has a modifier, have to add a dummy condition. lastRequirement.Type = RequirementType.AddSource; context.Trigger.Add(new Requirement { Left = new Field { Size = lastRequirement.Left.Size, Type = FieldType.Value, Value = 0 } }); lastRequirement = context.LastRequirement; } } lastRequirement.Operator = op; lastRequirement.Right = CreateFieldFromExpression(right); } else { error = ExecuteAchievementExpression(right, scope); if (error != null) { return(ParseErrorExpression.WrapError(error, "Invalid value", right)); } var extraRequirement = context.LastRequirement; ((IList <Requirement>)context.Trigger).RemoveAt(context.Trigger.Count - 1); var requirement = context.LastRequirement; if (requirement != null) { if (requirement.Type == RequirementType.AddAddress) { return(HandleAddAddressComparison(comparison, (IList <Requirement>)context.Trigger, op, extraRequirement)); } else if (context.Trigger.Count > 1 && context.Trigger.ElementAt(context.Trigger.Count - 2).Type == RequirementType.AddAddress) { // if left side is an AddAddress chain, but right side is a not, we have to keep the // dummy condition to prevent the AddAddress from modifying the memory address on the // right side. integers are handled above. requirement.Type = RequirementType.AddSource; extraRequirement.Right = extraRequirement.Left; extraRequirement.Left = new Field { Type = FieldType.Value, Value = 0 }; extraRequirement.Operator = op; context.Trigger.Add(extraRequirement); } else if (requirement.Operator != RequirementOperator.None) { // if left side is a complex expression (a * 4), add a new dummy condition for the comparison requirement.Type = RequirementType.AddSource; extraRequirement.Right = extraRequirement.Left; extraRequirement.Left = new Field { Type = FieldType.Value, Value = 0 }; extraRequirement.Operator = op; context.Trigger.Add(extraRequirement); } else { // no AddAddress on either side, just merge the conditions requirement.Operator = op; requirement.Right = extraRequirement.Left; } } } return(null); }
public void TestConcreteRequirements(Requirement requirement, bool expectedResult) { var context = new TestContext(); Assert.Equal(expectedResult, requirement.Evaluate(context, MyResource)); }