public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope)
        {
            TES5PlayerReference     player    = TES5ReferenceFactory.CreateReferenceToPlayer(globalScope);
            TES5ObjectCallArguments arguments = objectCallArgumentsFactory.CreateArgumentList(function.Arguments, codeScope, globalScope, multipleScriptsScope);

            return(objectCallFactory.CreateObjectCall(player, "SetDisplayName", arguments));
        }
        /*
         * Create a generic-purpose reference.
         */
        private ITES5Referencer CreateReference(string referenceName, TES5BasicType?typeForNewProperty, string?tes4ReferenceNameForType, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope, TES5LocalScope localScope)
        {
            if (TES5PlayerReference.EqualsPlayer(referenceName))
            {
                return(CreateReferenceToPlayer(globalScope));
            }

            Match match = ReferenceAndPropertyNameRegex.Match(referenceName);

            if (match.Success)
            {
                TES5ObjectProperty propertyReference = this.objectPropertyFactory.CreateObjectProperty(match.Groups[1].Value, match.Groups[2].Value, this, localScope, globalScope, multipleScriptsScope);
                return(propertyReference);
            }

            ITES5VariableOrProperty?property = localScope.TryGetVariable(referenceName);

            if (property == null)
            {
                property = globalScope.TryGetPropertyByOriginalName(referenceName); //todo rethink how to unify the prefix searching
                if (property == null)
                {
                    Nullable <int> tes4FormID   = null;
                    ITES5Type      propertyType =
                        typeForNewProperty != null ? typeForNewProperty :
                        GetPropertyTypeAndFormID(referenceName, tes4ReferenceNameForType, globalScope, multipleScriptsScope, out tes4FormID);
                    TES5Property propertyToAddToGlobalScope = TES5PropertyFactory.ConstructWithTES4FormID(referenceName, propertyType, referenceName, tes4FormID);
                    globalScope.AddProperty(propertyToAddToGlobalScope);
                    property = propertyToAddToGlobalScope;
                }
            }

            return(CreateReferenceToVariableOrProperty(property));
        }
        /*
         * Create a generic-purpose reference.
         */
        public ITES5Referencer CreateReference(string referenceName, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope, TES5LocalScope localScope)
        {
            if (TES5PlayerReference.EqualsPlayer(referenceName))
            {
                return(CreateReferenceToPlayer());
            }

            referenceName = PapyrusCompiler.FixReferenceName(referenceName);
            Match match = PropertyNameRegex.Match(referenceName);

            if (match.Success)
            {
                ITES5Referencer    mainReference     = this.CreateReference(match.Groups[1].Value, globalScope, multipleScriptsScope, localScope);
                TES5ObjectProperty propertyReference = this.objectPropertyFactory.CreateObjectProperty(multipleScriptsScope, mainReference, match.Groups[2].Value); //Todo rethink the prefix adding
                return(propertyReference);
            }

            ITES5VariableOrProperty property = localScope.GetVariable(referenceName);

            if (property == null)
            {
                property = globalScope.GetPropertyByName(referenceName); //todo rethink how to unify the prefix searching
                if (property == null)
                {
                    TES5Property propertyToAddToGlobalScope = null;
                    ITES5Type    specialConversion;
                    if (specialConversions.TryGetValue(referenceName, out specialConversion))
                    {
                        propertyToAddToGlobalScope = new TES5Property(referenceName, specialConversion, referenceName);
                    }

                    if (propertyToAddToGlobalScope == null)
                    {
                        if (!multipleScriptsScope.ContainsGlobalVariable(referenceName))
                        {
                            propertyToAddToGlobalScope = new TES5Property(referenceName, TES5BasicType.T_FORM, referenceName);
                        }
                        else
                        {
                            propertyToAddToGlobalScope = new TES5Property(referenceName, TES5BasicType.T_GLOBALVARIABLE, referenceName);
                        }
                    }
                    globalScope.AddProperty(propertyToAddToGlobalScope);
                    property = propertyToAddToGlobalScope;
                }
            }

            return(new TES5Reference(property));
        }
        public override ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope)
        {
            TES5LocalScope              localScope         = codeScope.LocalScope;
            TES4FunctionArguments       functionArguments  = function.Arguments;
            TES5ObjectCallArguments     convertedArguments = new TES5ObjectCallArguments();
            Dictionary <string, string> actorValueMap      = ActorValueMap.Map;
            ITES4StringValue            firstArg           = functionArguments[0];
            string firstArgString      = firstArg.StringValue;
            string firstArgStringLower = firstArgString.ToLower();

            switch (firstArgStringLower)
            {
            case "strength":
            case "intelligence":
            case "willpower":
            case "agility":
            case "endurance":
            case "personality":
            case "luck":
            {
                if (!TES5PlayerReference.EqualsPlayer(calledOn.Name))
                {
                    //We can"t convert those.. and shouldn"t be any, too.
                    throw new ConversionException("[" + TES4FunctionName + "] Cannot set attributes on non-player");
                }

                const string functionName = "SetValue";
                calledOn = this.referenceFactory.CreateReference(TES5ReferenceFactory.TES4Attr + PHPFunction.UCWords(firstArgStringLower), globalScope, multipleScriptsScope, localScope);
                ITES4StringValue secondArg = functionArguments[1];
                convertedArguments.Add(this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope));
                return(CreateObjectCall(calledOn, functionName, multipleScriptsScope, convertedArguments));
            }

            case "speed":
            {
                const string     functionName = "ForceMovementSpeed";
                ITES4StringValue secondArg    = functionArguments[1];
                convertedArguments.Add(this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope));
                return(CreateObjectCall(calledOn, functionName, multipleScriptsScope, convertedArguments));
            }

            case "fatigue":
            case "armorer":
            case "security":
            case "acrobatics":
            case "mercantile":
            case "mysticism":     //It doesn"t exist in Skyrim - defaulting to Illusion..
            case "blade":
            case "blunt":
            case "encumbrance":
            case "spellabsorbchance":
            case "resistfire":
            case "resistfrost":
            case "resistdisease":
            case "resistmagic":
            case "resistpoison":
            case "resistshock":
            {
                convertedArguments.Add(new TES5String(actorValueMap[firstArgStringLower]));
                ITES4StringValue secondArg = functionArguments[1];
                convertedArguments.Add(this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope));
                return(CreateObjectCall(calledOn, TES5FunctionName, multipleScriptsScope, convertedArguments));
            }

            case "aggression":
            {
                ITES4StringValue     secondArg            = functionArguments[1];
                object               secondArgObject      = secondArg.Data;
                Nullable <int>       secondArgNullableInt = secondArgObject as Nullable <int>;
                AST.Value.ITES5Value convertedArgument2;
                if (secondArgNullableInt != null)
                {        //WTM:  Change:  This apparently went unnoticed in the PHP version.  The second argument is not always an integer.  Sometimes its a variable reference.
                    //But the value of the variable will not be properly scaled to the values below, so the converted script may operate incorrectly.
                    int   secondArgInt = secondArgNullableInt.Value;
                    float newValue;
                    if (secondArgInt == 0)
                    {
                        newValue = 0;
                    }
                    else if (secondArgInt > 0 && secondArgInt < 50)
                    {
                        newValue = 1;
                    }
                    else if (secondArgInt >= 50 && secondArgInt < 80)
                    {
                        newValue = 2;
                    }
                    else
                    {
                        newValue = 3;
                    }
                    convertedArgument2 = new TES5Float(newValue);
                }
                else
                {
                    convertedArgument2 = this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope);
                }

                convertedArguments.Add(new TES5String(firstArgString));
                convertedArguments.Add(convertedArgument2);
                return(CreateObjectCall(calledOn, TES5FunctionName, multipleScriptsScope, convertedArguments));
            }

            case "confidence":
            {
                ITES4StringValue secondArg = functionArguments[1];
                int   secondArgData        = (int)secondArg.Data;
                float newValue;
                if (secondArgData == 0)
                {
                    newValue = 0;
                }
                else if (secondArgData > 0 && secondArgData < 30)
                {
                    newValue = 1;
                }
                else if (secondArgData >= 30 && secondArgData < 70)
                {
                    newValue = 2;
                }
                else if (secondArgData >= 70 && secondArgData < 99)
                {
                    newValue = 3;
                }
                else
                {
                    newValue = 4;
                }

                convertedArguments.Add(new TES5String(firstArgString));
                convertedArguments.Add(new TES5Float(newValue));
                return(CreateObjectCall(calledOn, TES5FunctionName, multipleScriptsScope, convertedArguments));
            }

            default:
            {
                convertedArguments.Add(new TES5String(firstArgString));
                ITES4StringValue secondArg = functionArguments[1];
                convertedArguments.Add(this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope));
                return(CreateObjectCall(calledOn, TES5FunctionName, multipleScriptsScope, convertedArguments));
            }
            }
        }
        public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope)
        {
            TES4FunctionArguments functionArguments = function.Arguments;
            TES5LocalScope        localScope        = codeScope.LocalScope;

            if (function.FunctionCall.FunctionName.Equals("modpcskill", StringComparison.OrdinalIgnoreCase))
            {
                /*
                 * MODPCSkill means we will need to call upon the player object
                 */
                calledOn = TES5ReferenceFactory.CreateReferenceToPlayer();
            }

            TES5ObjectCallArguments convertedArguments = new TES5ObjectCallArguments();
            var    actorValueMap       = ActorValueMap.Map;
            string firstArgString      = functionArguments[0].StringValue;
            string firstArgStringLower = firstArgString.ToLower();

            switch (firstArgStringLower)
            {
            case "strength":
            case "intelligence":
            case "willpower":
            case "agility":
            case "speed":
            case "endurance":
            case "personality":
            case "luck":
            {
                if (!TES5PlayerReference.EqualsPlayer(calledOn.Name))
                {
                    //We can"t convert those.. and shouldn"t be any, too.
                    throw new ConversionException(nameof(ModActorValueFactory) + ":  Cannot set attributes on non-player.  Name:  " + calledOn.Name + ", Argument:  " + firstArgString);
                }

                const string functionName     = "SetValue";
                string       tes4AttrFirstArg = TES5ReferenceFactory.TES4Attr + PHPFunction.UCWords(firstArgStringLower);

                /*
                 *  Switch out callee with the reference to attr
                 */
                ITES5Referencer  newCalledOn = this.referenceFactory.CreateReference(tes4AttrFirstArg, globalScope, multipleScriptsScope, localScope);
                ITES4StringValue secondArg   = functionArguments[1];
                ITES5Value       addedValue  = this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope);
                convertedArguments.Add(TES5ExpressionFactory.CreateArithmeticExpression(addedValue, TES5ArithmeticExpressionOperator.OPERATOR_ADD, this.referenceFactory.CreateReadReference(tes4AttrFirstArg, globalScope, multipleScriptsScope, localScope)));
                return(this.objectCallFactory.CreateObjectCall(newCalledOn, functionName, multipleScriptsScope, convertedArguments));
            }

            case "fatigue":
            case "armorer":
            case "security":
            case "acrobatics":
            case "mercantile":
            case "mysticism":     //It doesn"t exist in Skyrim - defaulting to Illusion..
            case "blade":
            case "blunt":
            case "encumbrance":
            case "spellabsorbchance":
            case "resistfire":
            case "resistfrost":
            case "resistdisease":
            case "resistmagic":
            case "resistpoison":
            case "resistshock":
            {
                const string functionName = "ModActorValue";
                convertedArguments.Add(new TES5String(actorValueMap[firstArgStringLower]));
                ITES4StringValue secondArg = functionArguments[1];
                convertedArguments.Add(this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope));
                return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, multipleScriptsScope, convertedArguments));
            }

            case "aggression":
            {
                const string     functionName = "ModActorValue";
                ITES4StringValue secondArg    = functionArguments[1];
                int secondArgData             = (int)secondArg.Data;
                int newValue;
                if (secondArgData < -80)
                {
                    newValue = -3;
                }
                else if (secondArgData >= -80 && secondArgData < -50)
                {
                    newValue = -2;
                }
                else if (secondArgData >= -50 && secondArgData < 0)
                {
                    newValue = -1;
                }
                else
                if (secondArgData == 0)
                {
                    newValue = 0;
                }
                else if (secondArgData > 0 && secondArgData < 50)
                {
                    newValue = 1;
                }
                else if (secondArgData >= 50 && secondArgData < 80)
                {
                    newValue = 2;
                }
                else
                {
                    newValue = 3;
                }

                convertedArguments.Add(new TES5String(firstArgString));
                convertedArguments.Add(new TES5Float(newValue));
                return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, multipleScriptsScope, convertedArguments));
            }

            case "confidence":
            {
                const string     functionName = "ModActorValue";
                ITES4StringValue secondArg    = functionArguments[1];
                int secondArgData             = (int)secondArg.Data;
                int newValue;
                if (secondArgData == -100)
                {
                    newValue = -4;
                }
                else if (secondArgData <= -70 && secondArgData > -100)
                {
                    newValue = -3;
                }
                else
                if (secondArgData <= -30 && secondArgData > -70)
                {
                    newValue = -2;
                }
                else
                if (secondArgData < 0 && secondArgData > -30)
                {
                    newValue = -1;
                }
                else
                if (secondArgData == 0)
                {
                    newValue = 0;
                }
                else if (secondArgData > 0 && secondArgData < 30)
                {
                    newValue = 1;
                }
                else
                if (secondArgData >= 30 && secondArgData < 70)
                {
                    newValue = 2;
                }
                else
                if (secondArgData >= 70 && secondArgData < 99)
                {
                    newValue = 3;
                }
                else
                {
                    newValue = 4;
                }

                convertedArguments.Add(new TES5String(firstArgString));
                convertedArguments.Add(new TES5Float(newValue));
                return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, multipleScriptsScope, convertedArguments));
            }

            default:
            {
                const string functionName = "ModActorValue";
                convertedArguments.Add(new TES5String(firstArgString));
                ITES4StringValue secondArg = functionArguments[1];
                convertedArguments.Add(this.valueFactory.CreateValue(secondArg, codeScope, globalScope, multipleScriptsScope));
                return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, multipleScriptsScope, convertedArguments));
            }
            }
        }
Beispiel #6
0
        public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope)
        {
            TES5LocalScope        localScope        = codeScope.LocalScope;
            const string          functionName      = "GetActorValue";
            TES4FunctionArguments functionArguments = function.Arguments;
            //@TODO - This should be fixed on expression-parsing level, with agression and confidence checks adjusted accordingly. There are no retail uses, so im not doing this for now ;)
            ITES4StringValue firstArg            = functionArguments[0];
            string           firstArgString      = firstArg.StringValue;
            string           firstArgStringLower = firstArgString.ToLower();

            switch (firstArgStringLower)
            {
            case "strength":
            case "intelligence":
            case "willpower":
            case "agility":
            case "speed":
            case "endurance":
            case "personality":
            case "luck":
            {
                if (!TES5PlayerReference.EqualsPlayer(calledOn.Name))
                {
                    if (calledOn.TES5Type.NativeType == TES5BasicType.T_ACTOR)        //WTM:  Change:  I added this if branch.
                    {
                        TES5ObjectCallArguments convertedArguments = new TES5ObjectCallArguments()
                        {
                            new TES5String(firstArgString)
                        };
                        return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, convertedArguments));
                    }
                    //We can"t convert those.. and shouldn"t be any, too.
                    throw new ConversionException(nameof(GetActorValueFactory) + ":  Cannot get attributes on non-player.  Name:  " + calledOn.Name + ", Argument:  " + firstArgString);
                }

                /*
                 *  Switch out callee with the reference to attr
                 */
                string tes4AttrFirstArg = TES5ReferenceFactory.GetTES4AttrPlusName(firstArgStringLower);
                return(this.referenceFactory.CreateReadReference(tes4AttrFirstArg, globalScope, multipleScriptsScope, localScope));
            }

            case "fatigue":
            case "armorer":
            case "security":
            case "acrobatics":
            case "mercantile":
            case "mysticism":     //It doesn"t exist in Skyrim - defaulting to Illusion..
            case "blade":
            case "blunt":
            case "encumbrance":
            case "spellabsorbchance":
            case "resistfire":
            case "resistfrost":
            case "resistdisease":
            case "resistmagic":
            case "resistpoison":
            case "resistshock":
            {
                TES5ObjectCallArguments convertedArguments = new TES5ObjectCallArguments()
                {
                    new TES5String(ActorValueMap.Map[firstArgStringLower])
                };
                return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, convertedArguments));
            }

            default:
            {
                TES5ObjectCallArguments convertedArguments = new TES5ObjectCallArguments()
                {
                    new TES5String(firstArgString)
                };
                return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, convertedArguments));
            }
            }
        }