Example #1
0
        private ParseErrorExpression ExecuteAchievementComparison(ComparisonExpression comparison, InterpreterScope scope)
        {
            _equalityModifiers.Clear();

            var context     = scope.GetContext <TriggerBuilderContext>();
            var insertIndex = context.Trigger.Count;

            var left  = comparison.Left;
            var right = comparison.Right;

            var op = GetRequirementOperator(comparison.Operation);

            if (left.Type == ExpressionType.IntegerConstant)
            {
                if (right.Type == ExpressionType.IntegerConstant)
                {
                    // comparing two constants, convert to always_true or always_false
                    var requirement = new Requirement
                    {
                        Left = new Field {
                            Type = FieldType.Value, Value = (uint)((IntegerConstantExpression)left).Value
                        },
                        Operator = op,
                        Right    = new Field {
                            Type = FieldType.Value, Value = (uint)((IntegerConstantExpression)right).Value
                        },
                    };

                    if (Evaluate(requirement))
                    {
                        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 = GetReversedRequirementOperator(op);
            }

            var error = ExecuteAchievementExpression(left, scope);

            if (error != null)
            {
                return(error);
            }

            var integerRight = right as IntegerConstantExpression;

            if (integerRight != null)
            {
                int newValue = integerRight.Value;

                // SubSource of a memory accessor may cause overflow - if comparing for less than,
                // modifiers should not be merged into the compare target
                if (_equalityModifiers.Count > 0 &&
                    (op == RequirementOperator.LessThan || op == RequirementOperator.LessThanOrEqual))
                {
                    bool hasSubSource = false;
                    for (int i = context.Trigger.Count - 2; i >= 0; i++)
                    {
                        var requirementType = context.Trigger.ElementAt(i).Type;
                        if (requirementType == RequirementType.SubSource)
                        {
                            hasSubSource = true;
                            break;
                        }
                        else if (requirementType != RequirementType.AddSource &&
                                 requirementType != RequirementType.AddHits)
                        {
                            break;
                        }
                    }

                    if (hasSubSource)
                    {
                        var last = context.Trigger.Last();
                        context.Trigger.Remove(last);
                        foreach (var modifier in _equalityModifiers)
                        {
                            if (modifier.Operation != MathematicOperation.Subtract && modifier.Operation != MathematicOperation.Add)
                            {
                                return(new ParseErrorExpression("Cannot normalize expression containing SubSource", left));
                            }

                            context.Trigger.Add(new Requirement
                            {
                                Type = (modifier.Operation == MathematicOperation.Subtract) ? RequirementType.AddSource : RequirementType.SubSource,
                                Left = new Field {
                                    Type = FieldType.Value, Value = (uint)modifier.Amount
                                },
                                Operator = RequirementOperator.None,
                                Right    = new Field()
                            });
                        }
                        context.Trigger.Add(last);

                        _equalityModifiers.Clear();
                    }
                }

                while (_equalityModifiers.Count > 0)
                {
                    var originalValue = newValue;
                    var modifier      = _equalityModifiers.Pop();
                    newValue = modifier.Apply(newValue);

                    var restoredValue = modifier.Remove(newValue);
                    switch (op)
                    {
                    case RequirementOperator.Equal:
                        if (restoredValue != originalValue)
                        {
                            return(new ParseErrorExpression("Result can never be true using integer math", comparison));
                        }
                        break;

                    case RequirementOperator.NotEqual:
                        if (restoredValue != originalValue)
                        {
                            return(new ParseErrorExpression("Result is always true using integer math", comparison));
                        }
                        break;

                    case RequirementOperator.GreaterThanOrEqual:
                        if (restoredValue != originalValue)
                        {
                            op = RequirementOperator.GreaterThan;
                        }
                        break;
                    }
                }

                var requirement = context.LastRequirement;
                requirement.Operator = op;
                requirement.Right    = new Field {
                    Size = requirement.Left.Size, Type = FieldType.Value, Value = (uint)newValue
                };
            }
            else
            {
                var leftModifiers = new Stack <ValueModifier>(_equalityModifiers.Reverse());
                _equalityModifiers.Clear();

                error = ExecuteAchievementExpression(right, scope);
                if (error != null)
                {
                    return(error);
                }

                if (leftModifiers.Count > 0 || _equalityModifiers.Count > 0)
                {
                    var rightValue = 1234567;
                    var leftValue  = rightValue;
                    while (leftModifiers.Count > 0)
                    {
                        var modifier = leftModifiers.Pop();
                        leftValue = ValueModifier.Apply(leftValue, MathematicExpression.GetOppositeOperation(modifier.Operation), modifier.Amount);
                    }

                    while (_equalityModifiers.Count > 0)
                    {
                        var modifier = _equalityModifiers.Pop();
                        rightValue = ValueModifier.Apply(rightValue, MathematicExpression.GetOppositeOperation(modifier.Operation), modifier.Amount);
                    }

                    var diff = leftValue - rightValue;
                    if (diff != 0)
                    {
                        var modifier = new Requirement();

                        if (diff < 0)
                        {
                            modifier.Left = new Field {
                                Type = FieldType.Value, Value = (uint)(-diff)
                            };
                            modifier.Type = RequirementType.SubSource;
                        }
                        else
                        {
                            modifier.Left = new Field {
                                Type = FieldType.Value, Value = (uint)diff
                            };
                            modifier.Type = RequirementType.AddSource;
                        }

                        ((IList <Requirement>)context.Trigger).Insert(insertIndex, modifier);
                    }
                }

                var extraRequirement = context.LastRequirement;
                context.Trigger.Remove(extraRequirement);

                var requirement = context.LastRequirement;
                if (requirement != null)
                {
                    requirement.Operator = op;
                    requirement.Right    = extraRequirement.Left;
                }
            }

            return(null);
        }
Example #2
0
        private ParseErrorExpression ExecuteAchievementMathematic(MathematicExpression mathematic, InterpreterScope scope)
        {
            var left      = mathematic.Left;
            var operation = mathematic.Operation;
            var context   = scope.GetContext <TriggerBuilderContext>();
            ParseErrorExpression error;

            ExpressionBase right;

            if (!mathematic.Right.ReplaceVariables(scope, out right))
            {
                return((ParseErrorExpression)right);
            }

            if (operation == MathematicOperation.Subtract && (right is FunctionCallExpression || right is MathematicExpression))
            {
                // if subtracting a non-integer, swap the order to perform a SubSource
                var newEqualityModifiers = new Stack <ValueModifier>();
                var oldEqualityModifiers = _equalityModifiers;
                _equalityModifiers = newEqualityModifiers;

                var requirements = new List <Requirement>();
                var innerContext = new TriggerBuilderContext()
                {
                    Trigger = requirements
                };
                var innerScope = new InterpreterScope(scope)
                {
                    Context = innerContext
                };

                // generate the condition for the right side
                error = ExecuteAchievementExpression(right, innerScope);
                _equalityModifiers = oldEqualityModifiers;
                if (error != null)
                {
                    return(error);
                }

                foreach (var requirement in requirements)
                {
                    switch (requirement.Type)
                    {
                    case RequirementType.None:
                    case RequirementType.AddSource:
                        requirement.Type = RequirementType.SubSource;
                        break;

                    case RequirementType.SubSource:
                        requirement.Type = RequirementType.AddSource;
                        break;

                    default:
                        return(new ParseErrorExpression("Cannot normalize expression for negation", mathematic));
                    }

                    context.Trigger.Add(requirement);
                }

                foreach (var modifier in newEqualityModifiers)
                {
                    switch (modifier.Operation)
                    {
                    case MathematicOperation.Add:
                        _equalityModifiers.Push(new ValueModifier(MathematicOperation.Subtract, modifier.Amount));
                        break;

                    case MathematicOperation.Subtract:
                        _equalityModifiers.Push(new ValueModifier(MathematicOperation.Add, modifier.Amount));
                        break;

                    default:
                        return(new ParseErrorExpression("Cannot normalize expression for negation", mathematic));
                    }
                }

                right     = mathematic.Left;
                operation = MathematicOperation.Add;
            }
            else
            {
                // generate the condition for the first expression
                error = ExecuteAchievementExpression(left, scope);
                if (error != null)
                {
                    return(error);
                }
            }

            var integerOperand = right as IntegerConstantExpression;

            if (integerOperand != null)
            {
                var oppositeOperation = MathematicExpression.GetOppositeOperation(operation);
                if (oppositeOperation == MathematicOperation.None)
                {
                    return(new ParseErrorExpression(String.Format("Cannot normalize expression to eliminate {0}", MathematicExpression.GetOperatorType(mathematic.Operation)), mathematic));
                }

                var priority = MathematicExpression.GetPriority(mathematic.Operation);
                if (priority != MathematicPriority.Add)
                {
                    if (context.Trigger.Count > 1)
                    {
                        var previousRequirementType = context.Trigger.ElementAt(context.Trigger.Count - 2).Type;
                        if (previousRequirementType == RequirementType.AddSource || previousRequirementType == RequirementType.SubSource)
                        {
                            return(new ParseErrorExpression(String.Format("Cannot normalize expression to eliminate {0}", MathematicExpression.GetOperatorType(mathematic.Operation)), mathematic));
                        }
                    }

                    if (_equalityModifiers.Any(e => MathematicExpression.GetPriority(e.Operation) != priority))
                    {
                        return(new ParseErrorExpression(String.Format("Cannot normalize expression to eliminate {0}", MathematicExpression.GetOperatorType(mathematic.Operation)), mathematic));
                    }
                }

                _equalityModifiers.Push(new ValueModifier(oppositeOperation, integerOperand.Value));
                return(null);
            }

            if (operation == MathematicOperation.Add)
            {
                foreach (var modifier in _equalityModifiers)
                {
                    if (MathematicExpression.GetPriority(modifier.Operation) != MathematicPriority.Add)
                    {
                        return(new ParseErrorExpression(String.Format("Cannot normalize expression to eliminate {0}", MathematicExpression.GetOperatorType(MathematicExpression.GetOppositeOperation(modifier.Operation))), mathematic));
                    }
                }

                // adding two memory accessors - make sure previous is AddSource or SubSource
                if (context.LastRequirement.Type != RequirementType.SubSource)
                {
                    context.LastRequirement.Type     = RequirementType.AddSource;
                    context.LastRequirement.Operator = RequirementOperator.None;
                    context.LastRequirement.Right    = new Field();
                }
            }
            else
            {
                return(new ParseErrorExpression(String.Format("Cannot normalize expression to eliminate {0}", MathematicExpression.GetOperatorType(mathematic.Operation)), mathematic));
            }

            // generate the condition for the second expression
            error = ExecuteAchievementExpression(right, scope);
            if (error != null)
            {
                error = new ParseErrorExpression(error.Message, mathematic);
            }
            return(error);
        }