示例#1
0
        /*
         * @throws ConversionException
         */
        public ITES5Type ResolveInferenceTypeByReferenceEdid(ITES5VariableOrProperty variable)
        {
            string edid = variable.ReferenceEDID;

            //WTM:  Change:  Without this if statement, SEBrithaurRef finds a reference
            //from qf_se35_01044c44_40_0 to SEBrithaurScript instead of
            //from qf_se35_01044c44_40_0 to SE35BrithaurScript
            //So the content of this if statement must be skipped.
            if (edid != "SEBrithaurRef")
            {
                //WTM:  Change:  I added the "FurnScript" (for qf_housebravil_01085480_10_0 and other house quests) and "QuestScript" (for MQDragonArmorQuestScript) items.
                List <string> namesToTry = new List <string>()
                {
                    edid, edid + "QuestScript", edid + "FurnScript", edid + "Script"
                };
                int edidLength = edid.Length;
                if (edid.Substring(edidLength - 3, 3).Equals("ref", StringComparison.OrdinalIgnoreCase))
                {
                    string tryAsRef = edid.Substring(0, edidLength - 3);
                    namesToTry.AddRange(new string[] { tryAsRef, tryAsRef + "Script" });
                }
                namesToTry = namesToTry.Distinct().ToList();
                string firstNameMatch = namesToTry.Where(n => this.otherScriptsLower.Contains(n.ToLower())).FirstOrDefault();
                if (firstNameMatch != null)
                {
                    return(TES5TypeFactory.MemberByValue(firstNameMatch));
                }
            }

            //If it"s not found, we"re forced to scan the ESM to see, how to resolve the ref name to script type
            return(this.esmAnalyzer.ResolveScriptTypeByItsAttachedName(variable.ReferenceEDID));
        }
示例#2
0
        /*
         * @throws ConversionTypeMismatchException
         */
        public ITES5Type GetScriptTypeByReferenceEdid(ITES5VariableOrProperty variable)
        {
            string?edid = variable.ReferenceEDID;

            if (edid == null)
            {
                throw new NullableException(nameof(edid));
            }
            //WTM:  Change:  The below section seemed to only introduce issues.

            /*
             * //WTM:  Change:  Without this if statement, SEBrithaurRef finds a reference
             * //from qf_se35_01044c44_40_0 to SEBrithaurScript instead of
             * //from qf_se35_01044c44_40_0 to SE35BrithaurScript
             * //So the content of this if statement must be skipped.
             * if (edid != "SEBrithaurRef")
             * {
             *  //WTM:  Change:  I added the "FurnScript" (for qf_housebravil_01085480_10_0 and other house quests) and "QuestScript" (for MQDragonArmorQuestScript) items.
             *  List<string> namesToTry = new List<string>() { edid, edid + "QuestScript", edid + "FurnScript", edid + "Script" };
             *  int edidLength = edid.Length;
             *  if (edid.Substring(edidLength - 3, 3).Equals("ref", StringComparison.OrdinalIgnoreCase))
             *  {
             *      string tryAsRef = edid.Substring(0, edidLength - 3);
             *      namesToTry.AddRange(new string[] { tryAsRef, tryAsRef + "Script" });
             *  }
             *  namesToTry = namesToTry.Distinct().ToList();
             *  string firstNameMatch = namesToTry.Where(n => this.otherScriptsLower.Contains(n.ToLower())).FirstOrDefault();
             *  if (firstNameMatch != null) { return TES5TypeFactory.MemberByValue(firstNameMatch, null, esmAnalyzer); }
             * }
             */
            //If it"s not found, we"re forced to scan the ESM to see, how to resolve the ref name to script type
            return(this.esmAnalyzer.GetScriptTypeByEDID(edid));
        }
示例#3
0
 /*
  * Inference the variable by its reference EDID
  *
  * @throws ConversionTypeMismatchException
  */
 public void InferenceVariableByReferenceEdid(ITES5VariableOrProperty variable, TES5MultipleScriptsScope multipleScriptsScope)
 {
     if (variable.TES5Type.AllowInference)
     {
         ITES5Type type = this.GetScriptTypeByReferenceEdid(variable);
         this.InferenceWithCustomType(variable, type, multipleScriptsScope);
     }
 }
示例#4
0
        private void InferenceWithCustomType(ITES5VariableOrProperty variable, ITES5Type type, TES5MultipleScriptsScope multipleScriptsScope)
        {
            /*
             * We"re referencing another script - find the script and make it a variable that property will track remotely
             */
            TES5ScriptHeader scriptHeader = multipleScriptsScope.GetScriptHeaderOfScript(type.OriginalName);

            variable.TrackRemoteScript(scriptHeader);
        }
示例#5
0
        /*
         * Inference the variable by its reference EDID
         *
         * @throws ConversionException
         */
        public void InferenceVariableByReferenceEdid(ITES5VariableOrProperty variable, TES5MultipleScriptsScope multipleScriptsScope)
        {
            //Check if it was inferenced to custom type already
            if (!variable.TES5Type.IsNativePapyrusType)
            {
                return; //Do not even try to inference a type which is already non-native.
            }

            this.InferenceWithCustomType(variable, this.ResolveInferenceTypeByReferenceEdid(variable), multipleScriptsScope);
        }
示例#6
0
        /*
         * Try to inference variable"s type with type.
         *
         *
         *  Needed for proxifying the properties to other scripts
         *  - Will return true if inferencing succeeded, false otherwise.
         * @throws ConversionException
         */
        private bool InferenceType(ITES5VariableOrProperty variable, ITES5Type type, TES5MultipleScriptsScope multipleScriptsScope)
        {
            if (!TES5InheritanceGraphAnalyzer.IsExtending(type, variable.TES5Type.NativeType))
            {
                return(false);
            }

            variable.TES5Type = type;
            return(true);
        }
        public TES5ObjectProperty CreateObjectProperty(TES5MultipleScriptsScope multipleScriptsScope, ITES5Referencer reference, string propertyName)
        {
            ITES5VariableOrProperty referencesTo = reference.ReferencesTo;

            this.typeInferencer.InferenceVariableByReferenceEdid(referencesTo, multipleScriptsScope);
            TES5Property       remoteProperty = multipleScriptsScope.GetPropertyFromScript(referencesTo.TES5Type.OriginalName, propertyName);
            TES5ObjectProperty objectProperty = new TES5ObjectProperty(reference, remoteProperty);

            return(objectProperty);
        }
        /*
         * 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));
        }
示例#9
0
 /*
  * Try to inference variable"s type with type.
  *
  *
  *  Needed for proxifying the properties to other scripts
  *  - Will return true if inferencing succeeded, false otherwise.
  * @throws ConversionTypeMismatchException
  */
 private void InferenceType(ITES5VariableOrProperty variable, TES5BasicType type)
 {
     if (!TES5InheritanceGraphAnalyzer.IsTypeOrExtendsTypeOrIsNumberType(type, variable.TES5Type.NativeType, false))
     {
         if (TES5InheritanceGraphAnalyzer.IsExtending(variable.TES5Type.NativeType, type))
         {
             return;
         }
         throw new ConversionTypeMismatchException("Could not extend " + variable.TES5Type.NativeType.Value + " to " + type.Value + ".");
     }
     if (variable.TES5Type.AllowInference)
     {
         variable.TES5Type = type;
     }
     else if (variable.TES5Type.AllowNativeTypeInference)
     {
         variable.TES5Type.NativeType = type;
     }
     else
     {
         throw new ConversionTypeMismatchException(variable.Name + " (" + variable.TES5DeclaredType.OriginalName + " : " + variable.TES5DeclaredType.NativeType.Name + ") could not be inferenced to a " + type.Name + " because inference was not allowed.");
     }
 }
        private void SetUpBranch(TES4CodeBlock block, TES5EventCodeBlock newBlock, TES5FunctionScope blockFunctionScope, ITES5VariableOrProperty variable, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope)
        {
            TES4BlockParameterList parameterList = block.BlockParameterList;

            if (parameterList == null)
            {
                return;
            }
            List <TES4BlockParameter> parameterListVariableList = parameterList.Parameters;
            TES4BlockParameter        tesEquippedTarget         = parameterListVariableList[0];
            TES5LocalScope            localScope   = newBlock.CodeScope.LocalScope;
            ITES5Referencer           newContainer = this.referenceFactory.CreateReadReference(tesEquippedTarget.BlockParameter, globalScope, multipleScriptsScope, localScope);
            TES5ComparisonExpression  expression   = TES5ExpressionFactory.CreateComparisonExpression(TES5ReferenceFactory.CreateReferenceToVariable(variable), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, newContainer);

            SetUpBranch(blockFunctionScope, newBlock, expression);
        }
 public TES5Reference(ITES5VariableOrProperty referencesTo)
 {
     this.ReferencesTo = referencesTo;
 }
        private TES5CodeScope SetUpBranch(TES4CodeBlock block, TES5CodeScope codeScope, TES5FunctionScope blockFunctionScope, ITES5VariableOrProperty variable, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope)
        {
            TES4BlockParameterList?parameterList = block.BlockParameterList;

            if (parameterList == null)
            {
                return(codeScope);
            }
            TES5Reference            variableReference      = TES5ReferenceFactory.CreateReferenceToVariableOrProperty(variable);
            TES5LocalScope           localScope             = codeScope.LocalScope;
            TES4BlockParameter       firstParameter         = parameterList.Parameters[0];
            ITES5Referencer          firstVariableReference = this.referenceFactory.CreateReadReference(firstParameter.BlockParameter, globalScope, multipleScriptsScope, localScope);
            TES5ComparisonExpression expression             = TES5ExpressionFactory.CreateComparisonExpression(variableReference, TES5ComparisonExpressionOperator.OPERATOR_EQUAL, firstVariableReference);

            return(SetUpBranch(blockFunctionScope, codeScope, expression));
        }
        public TES5CodeScope Modify(TES4CodeBlock block, TES5BlockList blockList, TES5FunctionScope blockFunctionScope, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope)
        {
            //https://cs.elderscrolls.com/index.php?title=Begin
            //WTM:  Change:  Added:  I reorganized this method and forced each event to account for the first Oblivion parameter.
            bool accountedForParameter = false;

            switch (block.BlockType.ToLower())
            {
            case "gamemode":
            case "scripteffectupdate":
            {
                TES5ObjectCall function = this.objectCallFactory.CreateRegisterForSingleUpdate(globalScope);
                codeScope.AddChunk(function);
                if (globalScope.ScriptHeader.ScriptType.NativeType == TES5BasicType.T_QUEST)
                {
                    TES5EventCodeBlock onInitBlock = TES5BlockFactory.CreateOnInit();
                    onInitBlock.AddChunk(function);
                    blockList.Add(onInitBlock);
                }
                break;
            }

            case "menumode":
            {
                TES5ComparisonExpression isInMenuModeComparisonExpression = GetIsInMenuModeComparisonExpression();
                codeScope             = SetUpBranch(blockFunctionScope, codeScope, isInMenuModeComparisonExpression);
                accountedForParameter = true;        //Skyrim handles menus differently than Oblivion's MenuType.
                break;
            }

            case "onactivate":
            {
                TES5EventCodeBlock onInitBlock = TES5BlockFactory.CreateOnInit();
                TES5ObjectCall     function    = this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToSelf(globalScope), "BlockActivation");
                onInitBlock.AddChunk(function);
                blockList.Add(onInitBlock);
                //WTM:  Change:  Added:  The following scripts erroneously add a parameter to their OnActivate block:
                //MS11BradonCorpse, SE01WaitingRoomScript, SE02LoveLetterScript, SE08Xeddefen03DoorSCRIPT, SE08Xeddefen05DoorSCRIPT, SE32TombEpitaph01SCRIPT, SEHillofSuicidesSCRIPT, SEXidPuzButton1, SEXidPuzButton2, SEXidPuzButton3, SEXidPuzButton4, SEXidPuzButtonSCRIPT, SEXidPuzHungerSCRIPT, XPEbroccaCrematorySCRIPT
                //But OnActivate does not take a parameter.  I'm trying to use the author's intended parameter instead of just ignoring it.
                codeScope             = SetUpBranch(block, codeScope, blockFunctionScope, "akActivateRef", globalScope, multipleScriptsScope);
                accountedForParameter = true;
                break;
            }


            case "onactorequip":
            {
                codeScope             = SetUpBranch(block, codeScope, blockFunctionScope, TES5LocalVariableParameterMeaning.CONTAINER, globalScope, multipleScriptsScope);
                accountedForParameter = true;
                break;
            }

            case "onadd":
            {
                codeScope             = SetUpBranch(block, codeScope, blockFunctionScope, "akNewContainer", globalScope, multipleScriptsScope);
                accountedForParameter = true;
                break;
            }

            case "onalarm":
            {
                //@INCONSISTENCE - We don"t account for CrimeType or Criminal.
                codeScope.AddChunk(this.objectCallFactory.CreateObjectCall(TES5StaticReferenceFactory.Debug, "Trace", new TES5ObjectCallArguments()
                    {
                        new TES5String("This function does not account for OnAlarm's CrimeType or Criminal.")
                    }));
                ITES5Value isAlarmed = TES5ExpressionFactory.CreateComparisonExpression(this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToSelf(globalScope), "IsAlarmed"), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Bool(true));
                codeScope             = SetUpBranch(blockFunctionScope, codeScope, isAlarmed);
                accountedForParameter = true;
                break;
            }

            /*
             * case "onalarm":
             * {
             *
             *  this.skyrimGroupEventName = "onhit";
             *
             *  if (this.eventArgs[1] != 3) {
             *      //Nothing eelse is supported really..
             *      this.omit = true;
             *      break;
             *  }
             *
             *  branch = new TES4ConditionalBranch();
             *  expression = new TES4Expression();
             *  leftConstant = new TES4Constant("akAggressor", "ObjectReference");
             *  //actionConstant        = new TES4Constant(this.eventArgs[1],"Package");
             *  actionConstant = TES4Factories.createReference(this.eventArgs[2], this);
             *
             *  expression.left_side = leftConstant;
             *  expression.right_side = actionConstant;
             *  expression.comparision_operator = TES4Expression.COMPARISION_OPERATOR_EQUAL;
             *
             *  codeBlock = new TES4CodeBlock();
             *  codeBlock.chunks = this.chunks;
             *
             *  branch.ifs[] = array(
             *      "rawExpression" => "SCRIPT_GENERATED",
             *      "expression" => expression,
             *      "codeBlock" => codeBlock
             *  );
             *  this.chunks = new TES4ChunkContainer();
             *  this.chunks.parent = this;
             *  this.chunks.addChunk(branch);
             *
             *  break;
             * }
             */

            case "ondeath":
            {
                codeScope             = SetUpBranch(block, codeScope, blockFunctionScope, "akKiller", globalScope, multipleScriptsScope);
                accountedForParameter = true;
                break;
            }

            case "ondrop":
            {
                codeScope             = SetUpBranch(block, codeScope, blockFunctionScope, "akOldContainer", globalScope, multipleScriptsScope);
                accountedForParameter = true;
                break;
            }

            case "onequip":
            case "onunequip":
            {
                codeScope             = SetUpBranch(block, codeScope, blockFunctionScope, "akActor", globalScope, multipleScriptsScope);
                accountedForParameter = true;
                break;
            }

            case "onhit":
            {
                codeScope             = SetUpBranch(block, codeScope, blockFunctionScope, "akAggressor", globalScope, multipleScriptsScope);
                accountedForParameter = true;
                break;
            }

            case "onhitwith":
            {
                TES4BlockParameterList?parameterList = block.BlockParameterList;
                if (parameterList != null)
                {
                    TES5LocalScope           localScope          = codeScope.LocalScope;
                    ITES5Referencer          hitWithCriteria     = this.referenceFactory.CreateReadReference(parameterList.Parameters[0].BlockParameter, globalScope, multipleScriptsScope, localScope);
                    TES5SignatureParameter   akSource            = localScope.FunctionScope.GetParameter("akSource");
                    TES5ComparisonExpression hitWithEqualsSource = TES5ExpressionFactory.CreateComparisonExpression(TES5ReferenceFactory.CreateReferenceToVariableOrProperty(akSource), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, hitWithCriteria);
                    TES5CodeScope            newCodeScope        = TES5CodeScopeFactory.CreateCodeScopeRoot(blockFunctionScope);
                    if (TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(TES5BasicType.T_AMMO, hitWithCriteria.TES5Type))
                    {
                        newCodeScope.AddChunk(this.objectCallFactory.CreateObjectCall(TES5StaticReferenceFactory.Debug, "Trace", new TES5ObjectCallArguments()
                            {
                                new TES5String("OBScript called OnHitWith using Ammo, but it's unlikely Papyrus will handle it properly.  When arrows are used, " + akSource.Name + " will be a bow.")
                            }));
                    }
                    newCodeScope.AddChunk(new TES5Branch(new TES5SubBranch(hitWithEqualsSource, codeScope)));
                    codeScope = newCodeScope;
                }
                accountedForParameter = true;
                break;
            }

            case "onmagiceffecthit":
            {
                codeScope             = SetUpBranch(block, codeScope, blockFunctionScope, "akEffect", globalScope, multipleScriptsScope);
                accountedForParameter = true;
                break;
            }

            case "onpackagestart":
            {
                codeScope             = SetUpBranch(block, codeScope, blockFunctionScope, "akNewPackage", globalScope, multipleScriptsScope);
                accountedForParameter = true;
                break;
            }

            case "onpackagechange":
            case "onpackagedone":
            case "onpackageend":
            {
                codeScope             = SetUpBranch(block, codeScope, blockFunctionScope, "akOldPackage", globalScope, multipleScriptsScope);
                accountedForParameter = true;
                break;
            }

            case "onsell":
            {
                codeScope             = SetUpBranch(block, codeScope, blockFunctionScope, "akSeller", globalScope, multipleScriptsScope);
                accountedForParameter = true;
                break;
            }

            case "onstartcombat":
            {
                codeScope             = SetUpBranch(block, codeScope, blockFunctionScope, "akTarget", globalScope, multipleScriptsScope);
                accountedForParameter = true;
                break;
            }

            case "ontrigger":
            {
                codeScope             = SetUpBranch(block, codeScope, blockFunctionScope, "akActivateRef", globalScope, multipleScriptsScope);
                accountedForParameter = true;
                break;
            }

            case "ontriggeractor":
            {
                TES4BlockParameterList?  parameterList                = block.BlockParameterList;
                TES5LocalScope           localScope                   = codeScope.LocalScope;
                ITES5VariableOrProperty  activator                    = localScope.GetVariableWithMeaning(TES5LocalVariableParameterMeaning.ACTIVATOR);
                TES5LocalVariable        castedToActor                = new TES5LocalVariable("akAsActor", TES5BasicType.T_ACTOR);
                TES5Reference            referenceToCastedVariable    = TES5ReferenceFactory.CreateReferenceToVariableOrProperty(castedToActor);
                TES5Reference            referenceToNonCastedVariable = TES5ReferenceFactory.CreateReferenceToVariableOrProperty(activator);
                TES5ComparisonExpression expression                   = TES5ExpressionFactory.CreateComparisonExpression(referenceToCastedVariable, TES5ComparisonExpressionOperator.OPERATOR_NOT_EQUAL, new TES5None());
                TES5CodeScope            newCodeScope                 = TES5CodeScopeFactory.CreateCodeScopeRoot(blockFunctionScope);
                newCodeScope.AddVariable(castedToActor);
                newCodeScope.AddChunk(TES5VariableAssignationFactory.CreateAssignation(referenceToCastedVariable, referenceToNonCastedVariable));
                TES5CodeScope outerBranchCode = TES5CodeScopeFactory.CreateCodeScopeRoot(blockFunctionScope);
                outerBranchCode.LocalScope.CopyVariablesFrom(codeScope.LocalScope);
                if (parameterList != null)
                {
                    ITES5Referencer          targetActor     = this.referenceFactory.CreateReadReference(parameterList.Parameters[0].BlockParameter, globalScope, multipleScriptsScope, localScope);
                    TES5ComparisonExpression interExpression = TES5ExpressionFactory.CreateComparisonExpression(TES5ReferenceFactory.CreateReferenceToVariableOrProperty(activator), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, targetActor);
                    outerBranchCode.AddChunk(new TES5Branch(new TES5SubBranch(interExpression, codeScope)));
                }
                else
                {
                    outerBranchCode.AddChunks(codeScope.CodeChunks);
                }
                newCodeScope.AddChunk(new TES5Branch(new TES5SubBranch(expression, outerBranchCode)));
                codeScope             = newCodeScope;
                accountedForParameter = true;
                break;
            }

            case "onload":
            case "onreset":
            case "ontriggermob":
            case "scripteffectstart":
            case "scripteffectfinish":
            {
                break;
            }

            default:
            {
                throw new InvalidOperationException(block.BlockType + " not found.");
            }
            }
            if (!accountedForParameter)
            {
                TES4BlockParameterList?parameterList = block.BlockParameterList;
                if (parameterList != null && parameterList.Parameters.Any())
                {
                    throw new ConversionException("Parameter not accounted for in " + block.BlockType + ":  " + parameterList.Parameters[0].BlockParameter);
                }
            }
            return(codeScope);
        }
 public static TES5Reference CreateReferenceToVariableOrProperty(ITES5VariableOrProperty variable)
 {
     return(new TES5Reference(variable));
 }