Exemple #1
0
        public override ParseErrorExpression BuildTrigger(TriggerBuilderContext context, InterpreterScope scope, FunctionCallExpression functionCall)
        {
            var count      = (IntegerConstantExpression)functionCall.Parameters.First();
            var comparison = functionCall.Parameters.ElementAt(1);

            return(BuildTriggerConditions(context, scope, comparison, count.Value));
        }
Exemple #2
0
        public override bool BuildMacro(RichPresenceDisplayFunction.RichPresenceDisplayContext context, InterpreterScope scope, out ExpressionBase result)
        {
            var macro = GetStringParameter(scope, "macro", out result);

            if (macro == null)
            {
                return(false);
            }

            var expression = GetParameter(scope, "expression", out result);

            if (expression == null)
            {
                return(false);
            }

            var value = TriggerBuilderContext.GetValueString(expression, scope, out result);

            if (value == null)
            {
                return(false);
            }

            var functionCall = scope.GetContext <FunctionCallExpression>();
            var valueFormat  = GetValueFormat(macro.Value);

            context.RichPresence.AddValueField(functionCall, macro.Value, valueFormat);

            result = new StringConstantExpression(String.Format("@{0}({1})", macro.Value, value));
            return(true);
        }
        public void TestGetConditionString(string input, string expected)
        {
            ExpressionBase   error;
            InterpreterScope scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope());

            scope.Context = new TriggerBuilderContext();

            var expression = Parse(input);

            ExpressionBase processed;

            Assert.That(expression.ReplaceVariables(scope, out processed), Is.True);

            var result = TriggerBuilderContext.GetConditionString(processed, scope, out error);

            if (error != null)
            {
                Assert.That(((ParseErrorExpression)error).InnermostError.Message, Is.EqualTo(expected));
            }
            else
            {
                Assert.That(error, Is.Null);
                Assert.That(result, Is.EqualTo(expected));
            }
        }
Exemple #4
0
        private List <Requirement> Evaluate(string input, string expectedError = null)
        {
            var requirements = new List <Requirement>();
            var funcDef      = new RepeatedFunction();

            var expression = ExpressionBase.Parse(new PositionalTokenizer(Tokenizer.CreateTokenizer(input)));

            Assert.That(expression, Is.InstanceOf <FunctionCallExpression>());
            var funcCall = (FunctionCallExpression)expression;

            ExpressionBase error;
            var            scope   = funcCall.GetParameters(funcDef, AchievementScriptInterpreter.GetGlobalScope(), out error);
            var            context = new TriggerBuilderContext {
                Trigger = requirements
            };

            scope.Context = context;

            ExpressionBase evaluated;

            Assert.That(funcDef.ReplaceVariables(scope, out evaluated), Is.True);

            if (expectedError == null)
            {
                Assert.That(funcDef.BuildTrigger(context, scope, funcCall), Is.Null);
            }
            else
            {
                var parseError = funcDef.BuildTrigger(context, scope, funcCall);
                Assert.That(parseError, Is.Not.Null);
                Assert.That(parseError.Message, Is.EqualTo(expectedError));
            }

            return(requirements);
        }
Exemple #5
0
        public void TestFunctionReference()
        {
            string input = "once(f)";

            var requirements = new List <Requirement>();
            var funcDef      = new OnceFunction();

            var expression = ExpressionBase.Parse(new PositionalTokenizer(Tokenizer.CreateTokenizer(input)));

            Assert.That(expression, Is.InstanceOf <FunctionCallExpression>());
            var funcCall = (FunctionCallExpression)expression;

            var scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope());

            scope.AssignVariable(new VariableExpression("f"), new FunctionReferenceExpression("f2"));

            ExpressionBase error;

            scope = funcCall.GetParameters(funcDef, scope, out error);
            var context = new TriggerBuilderContext {
                Trigger = requirements
            };

            scope.Context = context;

            ExpressionBase evaluated;

            Assert.That(funcDef.ReplaceVariables(scope, out evaluated), Is.True);
            funcCall = evaluated as FunctionCallExpression;

            var parseError = funcDef.BuildTrigger(context, scope, funcCall);

            Assert.That(parseError, Is.Not.Null);
            Assert.That(parseError.InnermostError.Message, Is.EqualTo("Function used like a variable"));
        }
Exemple #6
0
        private string ProcessValue(InterpreterScope scope, string parameter, out ExpressionBase result)
        {
            var expression = GetParameter(scope, parameter, out result);

            if (expression == null)
            {
                return(null);
            }

            var functionCallExpression = expression as FunctionCallExpression;

            if (functionCallExpression != null)
            {
                var functionDefinition = scope.GetFunction(functionCallExpression.FunctionName.Name);
                if (functionDefinition is MaxOfFunction)
                {
                    var builder = new StringBuilder();
                    foreach (var value in functionCallExpression.Parameters)
                    {
                        if (builder.Length > 0)
                        {
                            builder.Append('$');
                        }

                        builder.Append(TriggerBuilderContext.GetValueString(value, scope, out result));
                    }
                    return(builder.ToString());
                }
            }

            return(TriggerBuilderContext.GetValueString(expression, scope, out result));
        }
Exemple #7
0
        public override ParseErrorExpression BuildTrigger(TriggerBuilderContext context, InterpreterScope scope, FunctionCallExpression functionCall)
        {
            // add another TriggerBuilderContext scope to prevent optimizing the expression at this time
            var nestedScope = new InterpreterScope(scope)
            {
                Context = new TriggerBuilderContext()
            };

            return(base.BuildTrigger(context, nestedScope, functionCall));
        }
Exemple #8
0
        private string ProcessTrigger(InterpreterScope scope, string parameter, out ExpressionBase result)
        {
            var expression = GetParameter(scope, parameter, out result);

            if (expression == null)
            {
                return(null);
            }

            return(TriggerBuilderContext.GetConditionString(expression, scope, out result));
        }
Exemple #9
0
        public override ParseErrorExpression BuildTrigger(TriggerBuilderContext context, InterpreterScope scope, FunctionCallExpression functionCall)
        {
            var requirement = new Requirement();
            var address     = (IntegerConstantExpression)functionCall.Parameters.First();

            requirement.Left = new Field {
                Size = _size, Type = FieldType.MemoryAddress, Value = (uint)address.Value
            };
            context.Trigger.Add(requirement);
            return(null);
        }
        public void TestGetValueString(string input, string expected)
        {
            ExpressionBase   error;
            InterpreterScope scope = new InterpreterScope(AchievementScriptInterpreter.GetGlobalScope());

            scope.Context = new TriggerBuilderContext();

            var expression = Parse(input);
            var result     = TriggerBuilderContext.GetValueString(expression, scope, out error);

            Assert.That(error, Is.Null);
            Assert.That(result, Is.EqualTo(expected));
        }
        public override bool BuildMacro(RichPresenceDisplayFunction.RichPresenceDisplayContext context, InterpreterScope scope, out ExpressionBase result)
        {
            var name = GetStringParameter(scope, "name", out result);

            if (name == null)
            {
                return(false);
            }

            var expression = GetParameter(scope, "expression", out result);

            if (expression == null)
            {
                return(false);
            }

            var dictionary = GetDictionaryParameter(scope, "dictionary", out result);

            if (dictionary == null)
            {
                return(false);
            }

            var fallback = GetStringParameter(scope, "fallback", out result);

            if (fallback == null)
            {
                return(false);
            }

            var value = TriggerBuilderContext.GetValueString(expression, scope, out result);

            if (value == null)
            {
                return(false);
            }

            var functionCall = scope.GetContext <FunctionCallExpression>();

            var error = context.RichPresence.AddLookupField(functionCall, name.Value, dictionary, fallback);

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

            result = new StringConstantExpression(String.Format("@{0}({1})", name.Value, value));
            return(true);
        }
Exemple #12
0
        protected ParseErrorExpression BuildTriggerCondition(TriggerBuilderContext context, InterpreterScope scope, ExpressionBase condition)
        {
            var            builder = new ScriptInterpreterAchievementBuilder();
            ExpressionBase result;

            if (!TriggerBuilderContext.ProcessAchievementConditions(builder, condition, scope, out result))
            {
                return((ParseErrorExpression)result);
            }

            if (builder.AlternateRequirements.Count > 0)
            {
                return(new ParseErrorExpression(Name.Name + " does not support ||'d conditions", condition));
            }

            if (builder.CoreRequirements.Count > 1)
            {
                var last = builder.CoreRequirements.Last();
                foreach (var requirement in builder.CoreRequirements)
                {
                    if (requirement.Type == RequirementType.None && !ReferenceEquals(requirement, last))
                    {
                        requirement.Type = RequirementType.AndNext;
                    }
                }
            }

            ParseErrorExpression error = ValidateSingleCondition(builder.CoreRequirements);

            if (error != null)
            {
                return(new ParseErrorExpression(error, condition));
            }

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

            foreach (var requirement in builder.CoreRequirements)
            {
                context.Trigger.Add(requirement);
            }

            return(null);
        }
Exemple #13
0
        public override ParseErrorExpression BuildTrigger(TriggerBuilderContext context, InterpreterScope scope, FunctionCallExpression functionCall)
        {
            var accessor = (FunctionCallExpression)functionCall.Parameters.First();
            var error    = context.CallFunction(accessor, scope);

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

            var left = context.LastRequirement.Left;

            context.LastRequirement.Left = new Field {
                Size = left.Size, Type = _fieldType, Value = left.Value
            };
            return(null);
        }
Exemple #14
0
        public override ParseErrorExpression BuildTrigger(TriggerBuilderContext context, InterpreterScope scope, FunctionCallExpression functionCall)
        {
            var address = ((IntegerConstantExpression)functionCall.Parameters.ElementAt(1)).Value;

            var index = ((IntegerConstantExpression)functionCall.Parameters.First()).Value;

            if (index < 0 || index > 31)
            {
                return(new ParseErrorExpression("index must be between 0 and 31", functionCall.Parameters.First()));
            }

            address += index / 8;
            index   %= 8;

            FieldSize size;

            switch (index)
            {
            default:
            case 0: size = FieldSize.Bit0; break;

            case 1: size = FieldSize.Bit1; break;

            case 2: size = FieldSize.Bit2; break;

            case 3: size = FieldSize.Bit3; break;

            case 4: size = FieldSize.Bit4; break;

            case 5: size = FieldSize.Bit5; break;

            case 6: size = FieldSize.Bit6; break;

            case 7: size = FieldSize.Bit7; break;
            }

            var requirement = new Requirement();

            requirement.Left = new Field {
                Size = size, Type = FieldType.MemoryAddress, Value = (uint)address
            };
            context.Trigger.Add(requirement);
            return(null);
        }
Exemple #15
0
        protected override bool SetDisplayString(RichPresenceBuilder richPresence, string displayString, InterpreterScope scope, out ExpressionBase result)
        {
            var expression = GetParameter(scope, "condition", out result);

            if (expression == null)
            {
                return(false);
            }

            var condition = TriggerBuilderContext.GetConditionString(expression, scope, out result);

            if (condition == null)
            {
                return(false);
            }

            richPresence.AddConditionalDisplayString(condition, displayString);
            return(true);
        }
Exemple #16
0
        protected ParseErrorExpression BuildTriggerCondition(TriggerBuilderContext context, InterpreterScope scope, ExpressionBase condition)
        {
            var            builder = new ScriptInterpreterAchievementBuilder();
            ExpressionBase result;

            if (!TriggerBuilderContext.ProcessAchievementConditions(builder, condition, scope, out result))
            {
                switch (condition.Type)
                {
                case ExpressionType.Conditional:
                case ExpressionType.Comparison:
                    // allowed constructs should only report the inner error
                    return((ParseErrorExpression)result);

                default:
                    // non-allowed construct
                    return(new ParseErrorExpression("comparison did not evaluate to a valid comparison", condition)
                    {
                        InnerError = (ParseErrorExpression)result
                    });
                }
            }

            var error = builder.CollapseForSubClause();

            if (error != null)
            {
                return(new ParseErrorExpression(error.Message, condition));
            }

            error = ModifyRequirements(builder);
            if (error != null)
            {
                return(new ParseErrorExpression(error.Message, condition));
            }

            foreach (var requirement in builder.CoreRequirements)
            {
                context.Trigger.Add(requirement);
            }

            return(null);
        }
Exemple #17
0
        public override ParseErrorExpression BuildTrigger(TriggerBuilderContext context, InterpreterScope scope, FunctionCallExpression functionCall)
        {
            var accessor = (FunctionCallExpression)functionCall.Parameters.First();
            var error    = context.CallFunction(accessor, scope);

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

            var left = context.LastRequirement.Left;

            if (left.Type != FieldType.MemoryAddress)
            {
                return(new ParseErrorExpression("cannot apply multiple modifiers to memory accessor", functionCall));
            }

            context.LastRequirement.Left = new Field {
                Size = left.Size, Type = _fieldType, Value = left.Value
            };
            return(null);
        }
Exemple #18
0
        public override ParseErrorExpression BuildMacro(RichPresenceDisplayFunction.RichPresenceDisplayContext context, InterpreterScope scope, FunctionCallExpression functionCall)
        {
            var name       = (StringConstantExpression)functionCall.Parameters.First();
            var expression = functionCall.Parameters.ElementAt(1);
            var dictionary = (DictionaryExpression)functionCall.Parameters.ElementAt(2);

            ExpressionBase result;
            var            value = TriggerBuilderContext.GetValueString(expression, scope, out result);

            if (value == null)
            {
                return((ParseErrorExpression)result);
            }

            context.RichPresence.AddLookupField(name.Value, dictionary);

            context.DisplayString.Append('@');
            context.DisplayString.Append(name.Value);
            context.DisplayString.Append('(');
            context.DisplayString.Append(value);
            context.DisplayString.Append(')');
            return(null);
        }
Exemple #19
0
        protected ParseErrorExpression BuildTriggerConditions(TriggerBuilderContext context, InterpreterScope scope, ExpressionBase comparison, int count)
        {
            ParseErrorExpression error;

            var logicalComparison = comparison as ConditionalExpression;

            if (logicalComparison != null && logicalComparison.Operation == ConditionalOperation.Or)
            {
                error = EvaluateAddHits(context, scope, logicalComparison);
            }
            else
            {
                error = BuildTriggerCondition(context, scope, comparison);
            }

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

            context.LastRequirement.HitCount = (ushort)count;
            return(null);
        }
Exemple #20
0
        private ParseErrorExpression EvaluateAddHits(TriggerBuilderContext context, InterpreterScope scope, ConditionalExpression condition)
        {
            ExpressionBase result;

            var builder = new ScriptInterpreterAchievementBuilder();

            builder.CoreRequirements.Add(new Requirement()); // empty core requirement required for optimize call, we'll ignore it
            if (!TriggerBuilderContext.ProcessAchievementConditions(builder, condition, scope, out result))
            {
                return((ParseErrorExpression)result);
            }

            var requirements = new List <Requirement>();

            foreach (var altGroup in builder.AlternateRequirements)
            {
                var error = ValidateSingleCondition(altGroup);
                if (error != null)
                {
                    return(error);
                }

                var requirement = altGroup.First();
                if (requirement.Type != RequirementType.None)
                {
                    return(new ParseErrorExpression("modifier not allowed in multi-condition repeated clause"));
                }

                requirements.Add(requirement);
            }

            // the last item cannot have its own HitCount as it will hold the HitCount for the group.
            // if necessary, find one without a HitCount and make it the last.
            int index = requirements.Count - 1;

            if (requirements[index].HitCount > 0)
            {
                do
                {
                    index--;
                } while (index >= 0 && requirements[index].HitCount > 0);

                if (index == -1)
                {
                    // all requirements had HitCount limits, add a dummy item that's never true for the total HitCount
                    requirements.Add(new Requirement
                    {
                        Left = new Field {
                            Type = FieldType.Value, Value = 1
                        },
                        Operator = RequirementOperator.Equal,
                        Right    = new Field {
                            Type = FieldType.Value, Value = 0
                        }
                    });
                }
                else
                {
                    // found a requirement without a HitCount limit, move it to the last spot for the total HitCount
                    var requirement = requirements[index];
                    requirements.RemoveAt(index);
                    requirements.Add(requirement);
                }
            }

            // everything but the last becomes an AddHits
            for (int i = 0; i < requirements.Count - 1; i++)
            {
                requirements[i].Type = RequirementType.AddHits;
            }

            // load the requirements into the trigger
            foreach (var requirement in requirements)
            {
                context.Trigger.Add(requirement);
            }

            return(null);
        }
Exemple #21
0
        public override ParseErrorExpression BuildTrigger(TriggerBuilderContext context, InterpreterScope scope, FunctionCallExpression functionCall)
        {
            var address = functionCall.Parameters.ElementAt(1);
            var result  = BuildTrigger(context, scope, functionCall, address);

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

            var index = ((IntegerConstantExpression)functionCall.Parameters.First()).Value;

            if (index < 0 || index > 31)
            {
                return(new ParseErrorExpression("index must be between 0 and 31", functionCall.Parameters.First()));
            }

            var offset = (uint)index / 8;

            index %= 8;

            FieldSize size;

            switch (index)
            {
            default:
            case 0: size = FieldSize.Bit0; break;

            case 1: size = FieldSize.Bit1; break;

            case 2: size = FieldSize.Bit2; break;

            case 3: size = FieldSize.Bit3; break;

            case 4: size = FieldSize.Bit4; break;

            case 5: size = FieldSize.Bit5; break;

            case 6: size = FieldSize.Bit6; break;

            case 7: size = FieldSize.Bit7; break;
            }

            var lastRequirement = context.LastRequirement;

            if (lastRequirement.Left.IsMemoryReference)
            {
                lastRequirement.Left = new Field {
                    Size = size, Type = lastRequirement.Left.Type, Value = lastRequirement.Left.Value + offset
                }
            }
            ;
            if (lastRequirement.Right.IsMemoryReference)
            {
                lastRequirement.Right = new Field {
                    Size = size, Type = lastRequirement.Right.Type, Value = lastRequirement.Right.Value + offset
                }
            }
            ;
            return(null);
        }
    }
}
        public override ParseErrorExpression BuildTrigger(TriggerBuilderContext context, InterpreterScope scope, FunctionCallExpression functionCall)
        {
            var address = functionCall.Parameters.First();

            return(BuildTrigger(context, scope, functionCall, address));
        }
Exemple #23
0
        public override bool Evaluate(InterpreterScope scope, out ExpressionBase result)
        {
            var achievement = new ScriptInterpreterAchievementBuilder();

            var stringExpression = GetStringParameter(scope, "title", out result);

            if (stringExpression == null)
            {
                return(false);
            }
            achievement.Title = stringExpression.Value;

            stringExpression = GetStringParameter(scope, "description", out result);
            if (stringExpression == null)
            {
                return(false);
            }
            achievement.Description = stringExpression.Value;

            stringExpression = GetStringParameter(scope, "badge", out result);
            if (stringExpression == null)
            {
                return(false);
            }
            achievement.BadgeName = stringExpression.Value;

            var integerExpression = GetIntegerParameter(scope, "points", out result);

            if (integerExpression == null)
            {
                return(false);
            }
            achievement.Points = integerExpression.Value;

            integerExpression = GetIntegerParameter(scope, "id", out result);
            if (integerExpression == null)
            {
                return(false);
            }
            achievement.Id = integerExpression.Value;

            var trigger = GetParameter(scope, "trigger", out result);

            if (trigger == null)
            {
                return(false);
            }

            if (!TriggerBuilderContext.ProcessAchievementConditions(achievement, trigger, scope, out result))
            {
                if (result.Location.Start != trigger.Location.Start || result.Location.End != trigger.Location.End)
                {
                    var error = (ParseErrorExpression)result;
                    result = new ParseErrorExpression(error.Message, trigger)
                    {
                        InnerError = error
                    };
                }

                return(false);
            }

            var newAchievement = achievement.ToAchievement();
            var functionCall   = scope.GetOutermostContext <FunctionCallExpression>();

            if (functionCall != null)
            {
                newAchievement.SourceLine = functionCall.Location.Start.Line;
            }

            var context = scope.GetContext <AchievementScriptContext>();

            Debug.Assert(context != null);
            context.Achievements.Add(newAchievement);
            return(true);
        }
Exemple #24
0
        public override ParseErrorExpression BuildTrigger(TriggerBuilderContext context, InterpreterScope scope, FunctionCallExpression functionCall)
        {
            var comparison = functionCall.Parameters.First();

            return(BuildTriggerConditions(context, scope, comparison, 1));
        }
        protected ParseErrorExpression BuildTrigger(TriggerBuilderContext context, InterpreterScope scope, FunctionCallExpression functionCall, ExpressionBase address)
        {
            var requirement     = new Requirement();
            var integerConstant = address as IntegerConstantExpression;

            if (integerConstant != null)
            {
                requirement.Left = new Field {
                    Size = this.Size, Type = FieldType.MemoryAddress, Value = (uint)integerConstant.Value
                };
                context.Trigger.Add(requirement);
                return(null);
            }

            IntegerConstantExpression offsetConstant  = null;
            IntegerConstantExpression scalarConstant  = null;
            RequirementOperator       scalarOperation = RequirementOperator.None;
            var originalAddress = address;

            var funcCall = address as FunctionCallExpression;

            if (funcCall == null)
            {
                var mathematic = address as MathematicExpression;
                if (mathematic != null &&
                    (mathematic.Operation == MathematicOperation.Add || mathematic.Operation == MathematicOperation.Subtract))
                {
                    if (CountMathematicMemoryAccessors(mathematic, 2) >= 2)
                    {
                        return(new ParseErrorExpression("Cannot construct single address lookup from multiple memory references", address));
                    }

                    offsetConstant = mathematic.Right as IntegerConstantExpression;
                    if (offsetConstant != null)
                    {
                        address = mathematic.Left;
                    }
                    else
                    {
                        offsetConstant = mathematic.Left as IntegerConstantExpression;
                        if (offsetConstant != null)
                        {
                            address = mathematic.Right;
                        }
                    }

                    if (offsetConstant != null)
                    {
                        if (mathematic.Operation == MathematicOperation.Subtract)
                        {
                            offsetConstant = new IntegerConstantExpression(-offsetConstant.Value);
                        }
                    }

                    mathematic = address as MathematicExpression;
                }

                if (mathematic != null)
                {
                    switch (mathematic.Operation)
                    {
                    case MathematicOperation.Multiply:
                        scalarConstant = mathematic.Right as IntegerConstantExpression;
                        if (scalarConstant != null)
                        {
                            address         = mathematic.Left;
                            scalarOperation = RequirementOperator.Multiply;
                        }
                        else
                        {
                            scalarConstant = mathematic.Left as IntegerConstantExpression;
                            if (scalarConstant != null)
                            {
                                scalarOperation = RequirementOperator.Multiply;
                                address         = mathematic.Right;
                            }
                        }
                        break;

                    case MathematicOperation.Divide:
                        scalarConstant = mathematic.Right as IntegerConstantExpression;
                        if (scalarConstant != null)
                        {
                            address         = mathematic.Left;
                            scalarOperation = RequirementOperator.Divide;
                        }
                        break;

                    case MathematicOperation.BitwiseAnd:
                        scalarConstant = mathematic.Right as IntegerConstantExpression;
                        if (scalarConstant != null)
                        {
                            address         = mathematic.Left;
                            scalarOperation = RequirementOperator.BitwiseAnd;
                        }
                        break;
                    }
                }

                funcCall = address as FunctionCallExpression;
            }

            if (funcCall != null)
            {
                var funcDef = scope.GetFunction(funcCall.FunctionName.Name) as TriggerBuilderContext.FunctionDefinition;
                if (funcDef != null)
                {
                    if (funcDef is MemoryAccessorFunction || funcDef is PrevPriorFunction)
                    {
                        var error = funcDef.BuildTrigger(context, scope, funcCall);
                        if (error != null)
                        {
                            return(error);
                        }

                        var lastRequirement = context.LastRequirement;
                        lastRequirement.Type = RequirementType.AddAddress;

                        if (scalarConstant != null && scalarConstant.Value != 1)
                        {
                            lastRequirement.Operator = scalarOperation;
                            lastRequirement.Right    = new Field {
                                Size = FieldSize.DWord, Type = FieldType.Value, Value = (uint)scalarConstant.Value
                            };
                        }

                        // a memory reference without an offset has to be generated with a 0 offset.
                        uint offset = (offsetConstant != null) ? (uint)offsetConstant.Value : 0;

                        requirement.Left = new Field {
                            Size = this.Size, Type = FieldType.MemoryAddress, Value = offset
                        };
                        context.Trigger.Add(requirement);
                        return(null);
                    }
                }
            }

            var builder = new StringBuilder();

            builder.Append("Cannot convert to an address: ");
            originalAddress.AppendString(builder);

            return(new ParseErrorExpression(builder.ToString(), address));
        }
Exemple #26
0
        public override ParseErrorExpression BuildTrigger(TriggerBuilderContext context, InterpreterScope scope, FunctionCallExpression functionCall)
        {
            var error = base.BuildTrigger(context, scope, functionCall);

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

            ExpressionBase result;
            var            format = functionCall.Parameters.ElementAt(2);

            if (!format.ReplaceVariables(scope, out result))
            {
                return((ParseErrorExpression)result);
            }

            StringConstantExpression formatStr = result as StringConstantExpression;

            if (formatStr == null)
            {
                return(new ParseErrorExpression("format is not a string", format));
            }

            if (formatStr.Value != "raw")
            {
                if (scope.GetContext <ValueBuilderContext>() != null)
                {
                    return(new ParseErrorExpression("Value fields only support raw measured values", format));
                }

                if (formatStr.Value == "percent")
                {
                    context.LastRequirement.Type = RequirementType.MeasuredPercent;
                }
                else
                {
                    return(new ParseErrorExpression("Unknown format: " + formatStr.Value, format));
                }
            }

            var when = functionCall.Parameters.ElementAt(1);

            var builder = new ScriptInterpreterAchievementBuilder();

            if (!TriggerBuilderContext.ProcessAchievementConditions(builder, when, scope, out result))
            {
                return new ParseErrorExpression("when did not evaluate to a valid comparison", when)
                       {
                           InnerError = (ParseErrorExpression)result
                       }
            }
            ;

            error = builder.CollapseForSubClause();
            if (error != null)
            {
                return(error);
            }

            if (builder.CoreRequirements.Count != 1 || builder.CoreRequirements.First().Evaluate() != true)
            {
                foreach (var requirement in builder.CoreRequirements)
                {
                    if (requirement.Type == RequirementType.None || requirement.Type == RequirementType.AndNext)
                    {
                        requirement.Type = RequirementType.MeasuredIf;
                    }

                    context.Trigger.Add(requirement);
                }
            }

            return(null);
        }
    }
Exemple #27
0
        protected ParseErrorExpression BuildTriggerConditions(TriggerBuilderContext context, InterpreterScope scope, ExpressionBase comparison, int count)
        {
            ParseErrorExpression error;

            var condition = comparison as ConditionalExpression;

            if (condition != null && condition.Operation == ConditionalOperation.And)
            {
                // extract never() conditions from And sequence and build a ResetNextIf clause
                var            nonNeverExpressions = new List <ExpressionBase>();
                ExpressionBase neverExpression     = null;

                foreach (var clause in condition.Conditions)
                {
                    var functionCall = clause as FunctionCallExpression;
                    if (functionCall != null && functionCall.FunctionName.Name == "never")
                    {
                        if (neverExpression != null)
                        {
                            return(new ParseErrorExpression("Only one never() clause allowed inside " + Name.Name + "()", clause));
                        }

                        neverExpression = clause;
                    }
                    else
                    {
                        nonNeverExpressions.Add(clause);
                    }
                }

                if (neverExpression != null && nonNeverExpressions.Count > 0)
                {
                    // define a new scope with a nested context to prevent TriggerBuilderContext.ProcessAchievementConditions
                    // from optimizing out the ResetIf
                    var nestedContext = new TriggerBuilderContext();
                    nestedContext.Trigger = new List <Requirement>();
                    var innerScope = new InterpreterScope(scope);
                    innerScope.Context = nestedContext;

                    error = BuildTriggerCondition(nestedContext, innerScope, neverExpression);
                    if (error != null)
                    {
                        return(error);
                    }

                    nestedContext.LastRequirement.Type = RequirementType.ResetNextIf;
                    foreach (var requirement in nestedContext.Trigger)
                    {
                        context.Trigger.Add(requirement);
                    }

                    comparison = new ConditionalExpression(ConditionalOperation.And, nonNeverExpressions);
                }
            }

            error = BuildTriggerCondition(context, scope, comparison);
            if (error != null)
            {
                return(error);
            }

            context.LastRequirement.HitCount = (uint)count;
            return(null);
        }
Exemple #28
0
        protected ParseErrorExpression EvaluateCondition(TriggerBuilderContext context, InterpreterScope scope, ConditionalExpression condition)
        {
            ExpressionBase result;

            var builder = new ScriptInterpreterAchievementBuilder();

            if (!TriggerBuilderContext.ProcessAchievementConditions(builder, condition, scope, out result))
            {
                return((ParseErrorExpression)result);
            }

            if (builder.CoreRequirements.Any())
            {
                var error = ProcessOrNextSubClause(builder.CoreRequirements);
                if (error != null)
                {
                    return(error);
                }

                if (builder.AlternateRequirements.Count == 0)
                {
                    // everything was converted to an OrNext. convert the last back
                    builder.CoreRequirements.Last().Type = RequirementType.None;

                    // one of the alts was entirely promoted to Core. We only need to check for that.
                    foreach (var clause in builder.CoreRequirements)
                    {
                        context.Trigger.Add(clause);
                    }

                    return(null);
                }

                // core requirements have to be injected into each subclause as a series of AndNext's
                builder.CoreRequirements.Last().Type = RequirementType.AndNext;
            }

            var requirements = new List <ICollection <Requirement> >();

            foreach (var altGroup in builder.AlternateRequirements)
            {
                var error = ProcessOrNextSubClause(altGroup);
                if (error != null)
                {
                    return(error);
                }

                if (builder.CoreRequirements.Any())
                {
                    var merged = new List <Requirement>(builder.CoreRequirements);
                    merged.AddRange(altGroup);
                    requirements.Add(merged);
                }
                else
                {
                    requirements.Add(altGroup);
                }
            }

            // the last item cannot have its own HitCount as it will hold the HitCount for the group.
            // if necessary, find one without a HitCount and make it the last.
            int index = requirements.Count - 1;

            if (requirements[index].Last().HitCount > 0)
            {
                do
                {
                    index--;
                } while (index >= 0 && requirements[index].Last().HitCount > 0);

                if (index == -1)
                {
                    // all requirements had HitCount limits, add a dummy item that's never true for the total HitCount
                    requirements.Add(new Requirement[] { AlwaysFalseFunction.CreateAlwaysFalseRequirement() });
                }
                else
                {
                    // found a requirement without a HitCount limit, move it to the last spot for the total HitCount
                    var requirement = requirements[index];
                    requirements.RemoveAt(index);
                    requirements.Add(requirement);
                }
            }

            // if we can guarantee the individual requirements won't be true in the same frame, we can use AddHits
            // instead of OrNext to improve compatibility with older versions of RetroArch
            if (CanUseAddHits(requirements))
            {
                foreach (var requirement in requirements)
                {
                    foreach (var cond in requirement)
                    {
                        if (cond.Type == RequirementType.OrNext)
                        {
                            cond.Type = RequirementType.AddHits;
                        }
                    }
                }
            }
            else
            {
                // an AndNext in the first clause is acceptable, but once we see the first
                // OrNext, each clause must be a single logical condition as AndNext has the
                // same priority as OrNext and will not be processed first.
                for (int i = 1; i < requirements.Count; ++i)
                {
                    if (requirements[i].Any(r => r.Type == RequirementType.AndNext))
                    {
                        return(new ParseErrorExpression("Cannot join multiple AndNext chains with OrNext"));
                    }
                }
            }

            // everything was converted to an OrNext. convert the last back
            requirements.Last().Last().Type = RequirementType.None;

            // load the requirements into the trigger
            foreach (var requirement in requirements)
            {
                foreach (var clause in requirement)
                {
                    context.Trigger.Add(clause);
                }
            }

            return(null);
        }
Exemple #29
0
        public override ParseErrorExpression BuildTrigger(TriggerBuilderContext context, InterpreterScope scope, FunctionCallExpression functionCall)
        {
            ExpressionBase result;
            int            addHitsClauses = 0;
            int            subHitsClauses = 0;

            var requirements = new List <ICollection <Requirement> >();

            for (int i = 1; i < functionCall.Parameters.Count; ++i)
            {
                var condition             = functionCall.Parameters.ElementAt(i);
                var conditionRequirements = new List <Requirement>();
                var nestedContext         = new TriggerBuilderContext()
                {
                    Trigger = conditionRequirements
                };
                var modifier = RequirementType.AddHits;

                var funcCall = condition as FunctionCallExpression;
                if (funcCall != null && funcCall.FunctionName.Name == "deduct")
                {
                    var deductScope = funcCall.GetParameters(scope.GetFunction(funcCall.FunctionName.Name), scope, out result);
                    if (deductScope == null)
                    {
                        return((ParseErrorExpression)result);
                    }

                    condition = deductScope.GetVariable("comparison");
                    modifier  = RequirementType.SubHits;
                    ++subHitsClauses;
                }
                else
                {
                    ++addHitsClauses;
                }

                var error = BuildTriggerCondition(nestedContext, scope, condition);
                if (error != null)
                {
                    return(error);
                }

                conditionRequirements.Last().Type = modifier;
                requirements.Add(conditionRequirements);
            }

            // if no requirements were generated, we're done
            if (requirements.Count == 0)
            {
                return(null);
            }

            // if there's any SubHits clauses, add a dummy clause for the final count, regardless of whether
            // the AddHits clauses have hit targets.
            if (subHitsClauses > 0)
            {
                if (addHitsClauses == 0)
                {
                    return(new ParseErrorExpression("tally requires at least one non-deducted item"));
                }

                requirements.Add(new Requirement[] { AlwaysFalseFunction.CreateAlwaysFalseRequirement() });
            }

            // the last item cannot have its own HitCount as it will hold the HitCount for the group.
            // if necessary, find one without a HitCount and make it the last.
            AchievementBuilder.EnsureLastGroupHasNoHitCount(requirements);

            // load the requirements into the trigger
            foreach (var requirement in requirements)
            {
                foreach (var clause in requirement)
                {
                    context.Trigger.Add(clause);
                }
            }

            // the last item of each clause was set to AddHits, change the absolute last back to None
            context.LastRequirement.Type = RequirementType.None;

            // set the target hitcount
            var count = (IntegerConstantExpression)functionCall.Parameters.First();

            context.LastRequirement.HitCount = (uint)count.Value;

            return(null);
        }
Exemple #30
0
 public override ParseErrorExpression BuildTrigger(TriggerBuilderContext context, InterpreterScope scope, FunctionCallExpression functionCall)
 {
     context.Trigger.Add(CreateAlwaysTrueRequirement());
     return(null);
 }