/* * @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)); }
/* * @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)); }
/* * 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); } }
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); }
/* * 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); }
/* * 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)); }
/* * 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)); }