public void Run() { string[] scripts = this.buildTargets.GetScriptsToCompile(this.scriptName); //BuildSourceFilesCollection partitionedScripts = this.buildTargets.GetSourceFiles(scripts); TES5GlobalVariables globalVariables = this.esmAnalyzer.GlobalVariables; foreach (var buildTarget in this.buildTargets) { Dictionary <string, TES5GlobalScope> scriptsScopes = new Dictionary <string, TES5GlobalScope>(); foreach (var buildScript in scripts) { string scriptName = Path.GetFileNameWithoutExtension(buildScript); string sourcePath = buildTarget.GetSourceFromPath(scriptName); //string outputPath = buildTarget.GetTranspileToPath(scriptName); TES5GlobalScope globalScope = buildTarget.BuildScope(sourcePath, globalVariables); scriptsScopes.Add(scriptName, globalScope); } TES5MultipleScriptsScope multipleScriptsScope = new TES5MultipleScriptsScope(scriptsScopes.Values, globalVariables); foreach (var buildScript in scripts) { string scriptName = Path.GetFileNameWithoutExtension(buildScript); string sourcePath = buildTarget.GetSourceFromPath(scriptName); string outputPath = buildTarget.GetTranspileToPath(scriptName); TES5GlobalScope globalScope = buildTarget.BuildScope(sourcePath, globalVariables); buildTarget.Transpile(sourcePath, outputPath, globalScope, multipleScriptsScope); } } }
/* * Extracts implicit reference from calls. * Returns a reference from calls like: * Enable * Disable * Activate * GetInFaction whatsoever */ public ITES5Referencer ExtractImplicitReference(TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope, TES5LocalScope localScope) { ITES5Type type = globalScope.ScriptHeader.BasicScriptType; if (type == TES5BasicType.T_OBJECTREFERENCE || type == TES5BasicType.T_ACTOR)//Change: WTM: Added Actor here. { return(CreateReferenceToSelf(globalScope)); } else if (type == TES5BasicType.T_ACTIVEMAGICEFFECT) { TES5SelfReference self = CreateReferenceToSelf(globalScope); return(this.objectCallFactory.CreateObjectCall(self, "GetTargetActor", multipleScriptsScope)); } else if (type == TES5BasicType.T_QUEST) { //todo - this should not be done like this //we should actually not try to extract the implicit reference on the non-reference oblivion functions like "stopQuest" //think of this line as a hacky way to just get code forward. return(CreateReferenceToSelf(globalScope)); } else if (type == TES5BasicType.T_TOPICINFO) { /* * TIF Fragments */ return(this.CreateReadReference("akSpeakerRef", globalScope, multipleScriptsScope, localScope)); } throw new ConversionException("Cannot extract implicit reference - unknown basic script type."); }
private void InferenceTypeOfCalledObject(TES5ObjectCall objectCall, TES5MultipleScriptsScope multipleScriptsScope) { ITES5Type inferencableType = objectCall.AccessedObject.TES5Type.NativeType; /* * Check if we have something to inference inside the code, not some static class or method call return */ if (objectCall.AccessedObject.ReferencesTo != null) { //this is not "exactly" nice solution, but its enough. For now. ITES5Type inferenceType = TES5InheritanceGraphAnalyzer.FindTypeByMethod(objectCall); if (inferencableType == null) { throw new ConversionException("Cannot inference a null type"); } if (inferencableType == inferenceType) { return; //We already have the good type. } if (this.InferenceType(objectCall.AccessedObject.ReferencesTo, inferenceType, multipleScriptsScope)) { return; } } }
/* * Add initial code to the blocks and return the scope in which conversion should occur * Sometimes, we want to add a bit of code before the converted code, or want to encapsulate whole converted code * with a branch or so - this is a place to do it. * * * * Scope in which we want for conversion to happen */ public TES5CodeScope AddInitialCode(TES5MultipleScriptsScope multipleScriptsScope, TES5GlobalScope globalScope, TES5EventCodeBlock eventCodeBlock) { switch (eventCodeBlock.BlockName) { case "OnUpdate": { if (globalScope.ScriptHeader.BasicScriptType == TES5BasicType.T_QUEST) { TES5Branch branch = TES5BranchFactory.CreateSimpleBranch(TES5ExpressionFactory.CreateComparisonExpression(this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToSelf(globalScope), "IsRunning", multipleScriptsScope, new TES5ObjectCallArguments()), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Bool(false)), eventCodeBlock.CodeScope.LocalScope); //Even though we"d like this script to not do anything at this time, it seems like sometimes condition races, so we"re putting it into a loop anyways but with early return bailout branch.MainBranch.CodeScope.AddChunk(this.objectCallFactory.CreateRegisterForSingleUpdate(globalScope, multipleScriptsScope)); branch.MainBranch.CodeScope.AddChunk(new TES5Return()); eventCodeBlock.AddChunk(branch); return(eventCodeBlock.CodeScope); } /*else if (globalScope.ScriptHeader.BasicScriptType== TES5BasicType.T_OBJECTREFERENCE) * { * TES5LocalScope localScope = eventCodeBlock.CodeScope.LocalScope; * TES5Branch branch = TES5BranchFactory.CreateSimpleBranch(TES5ExpressionFactory.CreateComparisonExpression(this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToSelf(globalScope), "GetParentCell", multipleScriptsScope, new TES5ObjectCallArguments()), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToPlayer(), "GetParentCell", multipleScriptsScope, new TES5ObjectCallArguments())), localScope); * eventCodeBlock.AddChunk(branch); * return branch.MainBranch.CodeScope; * }*/ else { return(eventCodeBlock.CodeScope); } } default: { return(eventCodeBlock.CodeScope); } } }
/* * Inference the type by analyzing the object call. * Please note: It is not able to analyze calls to another scripts, but those weren"t used in oblivion anyways */ public void InferenceObjectByMethodCall(TES5ObjectCall objectCall, TES5MultipleScriptsScope multipleScriptsScope) { this.InferenceTypeOfCalledObject(objectCall, multipleScriptsScope); if (objectCall.Arguments != null) { this.InferenceTypeOfMethodArguments(objectCall, 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); }
private void CreateActiveStateBlock(TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope, out TES5State state, out TES5EventCodeBlock onUpdate) { state = CreateState("ActiveState", false); TES5EventCodeBlock onBeginState = CreateEventCodeBlock("OnBeginState"); onBeginState.CodeScope.CodeChunks.Add(this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToSelf(globalScope), "OnUpdate", multipleScriptsScope)); state.AddBlock(onBeginState); onUpdate = CreateEventCodeBlock("OnUpdate"); state.AddBlock(onUpdate); }
private void InferenceTypeOfMethodArguments(TES5ObjectCall objectCall, TES5MultipleScriptsScope multipleScriptsScope) { /* * Inference the arguments */ int argumentIndex = 0; ITES5Type calledOnType = objectCall.AccessedObject.TES5Type.NativeType; foreach (ITES5Value argument in objectCall.Arguments) { /* * Get the argument type according to TES5Inheritance graph. */ ITES5Type argumentTargetType = TES5InheritanceGraphAnalyzer.FindTypeByMethodParameter(calledOnType, objectCall.FunctionName, argumentIndex); if (argument.TES5Type != argumentTargetType) { /* * todo - maybe we should move getReferencesTo() to TES5Value and make all of the rest TES5Values just have null references as they do not reference anything? :) */ ITES5Referencer referencerArgument = argument as ITES5Referencer; if (referencerArgument != null && TES5InheritanceGraphAnalyzer.IsExtending(argumentTargetType, argument.TES5Type.NativeType)) { //HACKY! this.InferenceType(referencerArgument.ReferencesTo, argumentTargetType, multipleScriptsScope); } else { //So there"s one , one special case where we actually have to cast a var from one to another even though they are not ,,inheriting" from themselves, because they are primitives. //Scenario: there"s an T_INT argument, and we feed it with a T_FLOAT variable reference. It won"t work :( //We need to cast it on call level ( NOT inference it ) to make it work and not break other possible scenarios ( more specifically, when a float would be inferenced to int and there"s a //float assigment somewhere in the code ) if (argumentTargetType == TES5BasicType.T_INT && argument.TES5Type == TES5BasicType.T_FLOAT) { TES5Castable argumentCastable = argument as TES5Castable; if (argumentCastable != null) { //HACKY! When we"ll clean up this interface, it will dissapear :) argumentCastable.ManualCastTo = argumentTargetType; } } else if ( !TES5InheritanceGraphAnalyzer.IsExtending(argument.TES5Type, argumentTargetType) && !TES5InheritanceGraphAnalyzer.IsNumberTypeOrBoolAndInt(argument.TES5Type, argumentTargetType) && !(argument is TES5None && TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(argumentTargetType, (new TES5None()).TES5Type))) { bool expected = objectCall.AccessedObject.TES5Type.OriginalName == "TES4TimerHelper" && objectCall.FunctionName == "LegacySay"; throw new ConversionException("Argument type mismatch at " + objectCall.FunctionName + " index " + argumentIndex + ". Expected " + argumentTargetType.OriginalName + ". Found " + argument.TES5Type.OriginalName + ".", expected: expected); } } } argumentIndex++; } }
private void CreateActivationStates(TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope, out TES5BlockList blocks, out TES5EventCodeBlock onUpdate) { TES5State activeState; CreateActiveStateBlock(globalScope, multipleScriptsScope, out activeState, out onUpdate); TES5State inactiveState = CreateInactiveStateBlock(); TES5EventCodeBlock onCellAttach = CreateEventCodeBlock("OnCellAttach"); onCellAttach.CodeScope.AddChunk(objectCallFactory.CreateGotoState("ActiveState", globalScope, multipleScriptsScope)); TES5EventCodeBlock onCellDetach = CreateEventCodeBlock("OnCellDetach"); onCellDetach.CodeScope.AddChunk(objectCallFactory.CreateGotoState("InactiveState", globalScope, multipleScriptsScope)); blocks = new TES5BlockList() { activeState, inactiveState, onCellAttach, onCellDetach }; }
/* * Extracts implicit reference from calls. * Returns a reference from calls like: * Enable * Disable * Activate * GetInFaction whatsoever */ public ITES5Referencer ExtractImplicitReference(TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope, TES5LocalScope localScope) { ITES5Type type = globalScope.ScriptHeader.ScriptType.NativeType; if (type == TES5BasicType.T_ACTIVEMAGICEFFECT) { TES5SelfReference self = CreateReferenceToSelf(globalScope); return(this.objectCallFactory.CreateObjectCall(self, "GetTargetActor")); } if (type == TES5BasicType.T_QUEST) { //todo - this should not be done like this //we should actually not try to extract the implicit reference on the non-reference oblivion functions like "stopQuest" //think of this line as a hacky way to just get code forward. return(CreateReferenceToSelf(globalScope)); } if (type == TES5BasicType.T_TOPICINFO) { //TIF Fragments return(this.CreateReadReference("akSpeakerRef", globalScope, multipleScriptsScope, localScope)); } //WTM: Change: I made this the new default result instead of the previous algorithm of exhaustively listing types and throwing an exception if no type matches. return(CreateReferenceToSelf(globalScope)); }
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES5LocalScope localScope = codeScope.LocalScope; TES4FunctionArguments functionArguments = function.Arguments; ITES5Referencer fameReference = this.referenceFactory.CreateReadReference("Fame", globalScope, multipleScriptsScope, localScope); TES5ObjectCallArguments fameArguments = new TES5ObjectCallArguments(); TES5ArithmeticExpression arithmeticExpression = TES5ExpressionFactory.CreateArithmeticExpression(fameReference, TES5ArithmeticExpressionOperator.OPERATOR_ADD, new TES5Integer(((TES4Integer)functionArguments[0]).IntValue)); fameArguments.Add(arithmeticExpression); return(this.objectCallFactory.CreateObjectCall(this.referenceFactory.CreateReference("Fame", globalScope, multipleScriptsScope, localScope), "SetValue", multipleScriptsScope, fameArguments)); }
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES4FunctionArguments functionArguments = function.Arguments; ITES4StringValue argument0 = functionArguments[0]; TES5ObjectCallArguments functionArgs = new TES5ObjectCallArguments() { this.valueFactory.CreateValue(argument0, codeScope, globalScope, multipleScriptsScope), new TES5Bool(true) }; return(this.objectCallFactory.CreateObjectCall(calledOn, "SetAlpha", functionArgs)); }
public void execute(string buildPath = Build.DEFAULT_BUILD_PATH, bool skipParsing = false, string mode = "strict") { set_time_limit(10800); // 3 hours is the maximum for this command. Need more? You really screwed something, full suite for all Oblivion vanilla data takes 20 minutes. :) float threshold; switch (mode) { case "sloppy": { threshold = 0.5f; break; } case "normal": { threshold = 0.85f; break; } case "strict": default: { threshold = 0.95f; break; } case "perfect": { threshold = 1; break; } } if (!skipParsing) { SyntaxErrorCleanParser parser = new SyntaxErrorCleanParser(new TES4ObscriptCodeGrammar()); //parser = new Parser(new TES4OBScriptGrammar()); TES4ToTES5ASTTIFFragmentConverter converter = TES4ToTES5ASTTIFFragmentConverterFactory.GetConverter(new Build(buildPath)); string inputFolder = "./Fragments/TIF/fragments/"; string outputFolder = "./Fragments/TIF/PapyrusFragments/"; string[] scandir = Directory.GetFiles(inputFolder); int success = 0, total = 0; Dictionary <string, TES5MultipleScriptsScope> ASTTable = new Dictionary <string, TES5MultipleScriptsScope>(); Console.WriteLine("Lexing and parsing.."); int totalNumber = scandir.Length; foreach (var scriptPath in scandir) { if (!scriptPath.EndsWith(".txt")) { continue; } if ((total % 10) == 0) { Console.WriteLine(total + "/" + totalNumber + "..."); } string scriptFileName = scriptPath.Substring(0, scriptPath.Length - 4); string outputScriptPath = scriptFileName + ".psc"; total++; try { Console.WriteLine(scriptFileName + "..."); FragmentLexer lexer = new FragmentLexer(); ArrayTokenStream tokens = lexer.lex(File.ReadAllText(path)); TES4VariableDeclarationList variableList = this.fragmentsReferencesBuilder.buildVariableDeclarationList(inputFolder + scriptFileName + ".references"); TES5MultipleScriptsScope AST = (TES5MultipleScriptsScope)parser.ParseWithFixLogic(tokens); ASTTable[scriptPath] = AST; TES5Target TES5AST = converter.convert(scriptFileName, variableList, AST); string outputScript = TES5AST.output(); File.WriteAllText(outputFolder + outputScriptPath, outputScript); Process.Start("lua", "\"Utilities/beautifier.lua\" \"" + outputFolder + outputScriptPath + "\""); success++; } catch (Exception e) { Console.WriteLine(scriptPath + "\r\n" + e.GetType().FullName + ": " + e.Message + "\r\n"); continue; } } float successRate = (float)success / total; if (successRate < threshold) { float percent = (float)Math.Round(successRate * 100); Console.WriteLine("ERROR: Build failed on parsing step in " + mode + " mode. The rate is " + success + "/" + total + " (" + percent + " %)"); return; } Console.WriteLine("Parsing in " + mode + " mode succedeed (rate " + success + "/" + total + "). Copying Skyrim scripts and parsed papyrus fragments to build folder..."); } Console.WriteLine("Build in " + mode + " mode succeeded!"); }
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES5LocalScope localScope = codeScope.LocalScope; TES4FunctionArguments functionArguments = function.Arguments; //This has to be a write-action reference, not a read reference! ITES5Referencer fameReference = this.referenceFactory.CreateReference("Fame", globalScope, multipleScriptsScope, localScope); TES5ObjectCallArguments fameArguments = new TES5ObjectCallArguments() { this.valueFactory.CreateValue(functionArguments[0], codeScope, globalScope, multipleScriptsScope) }; TES5ObjectCall newFunction = this.objectCallFactory.CreateObjectCall(fameReference, "SetValue", fameArguments); return(newFunction); }
public TES5CodeChunkCollection CreateCodeChunk(TES4VariableAssignation chunk, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES5CodeChunkCollection codeChunkCollection = new TES5CodeChunkCollection(); string referenceName = chunk.Reference.StringValue; ITES5Referencer reference = this.referenceFactory.CreateReference(referenceName, globalScope, multipleScriptsScope, codeScope.LocalScope); ITES5Value value = this.valueFactory.CreateValue(chunk.Value, codeScope, globalScope, multipleScriptsScope); if (reference.TES5Type == TES5BasicType.T_GLOBALVARIABLE) { //if the reference is in reality a global variable, we will need to convert it by creating a Reference.SetValue(value); call //Object call creation TES5ObjectCallArguments objectCallArguments = new TES5ObjectCallArguments() { value }; TES5ObjectCall objectCall = this.objectCallFactory.CreateObjectCall(reference, "SetValue", objectCallArguments); codeChunkCollection.Add(objectCall); } else { if (reference.ReferencesTo == null) { throw new NullableException(nameof(reference.ReferencesTo)); } if (!reference.ReferencesTo.TES5Type.IsPrimitive && value.TES5Type.IsPrimitive) { //Hacky! TES5IntegerOrFloat?valueNumber = value as TES5IntegerOrFloat; if (valueNumber != null && valueNumber.ConvertedIntValue == 0) { value = new TES5None(); } } TES5VariableAssignation assignation = TES5VariableAssignationFactory.CreateAssignation(reference, value); this.typeInferencer.InferenceObjectByAssignation(reference, value); codeChunkCollection.Add(assignation); //post analysis. //Todo - rethink the prefix here ITES5Referencer?referencerValue = value as ITES5Referencer; if (referencerValue != null && referencerValue.Name == TES5Property.AddPropertyNameSuffix(TES5ReferenceFactory.MESSAGEBOX_VARIABLE_CONST)) { /* * Create block: * variable = this.TES4_MESSAGEBOX_RESULT; ; assignation * if(variable != -1) ; branch, expression * this.TES4_MESSAGEBOX_RESULT = -1; ; reassignation * endIf */ TES5Integer negativeOne = new TES5Integer(-1); TES5ComparisonExpression expression = TES5ExpressionFactory.CreateComparisonExpression(reference, TES5ComparisonExpressionOperator.OPERATOR_NOT_EQUAL, negativeOne); TES5VariableAssignation reassignation = TES5VariableAssignationFactory.CreateAssignation(referencerValue, negativeOne); TES5Branch branch = TES5BranchFactory.CreateSimpleBranch(expression, codeScope.LocalScope); branch.MainBranch.CodeScope.AddChunk(reassignation); codeChunkCollection.Add(branch); } } return(codeChunkCollection); }
public void Modify(TES4CodeBlock block, TES5BlockList blockList, TES5EventCodeBlock newBlock, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES5FunctionScope blockFunctionScope = newBlock.FunctionScope; switch (block.BlockType.ToLower()) { case "gamemode": case "scripteffectupdate": { TES5ObjectCall function = this.objectCallFactory.CreateRegisterForSingleUpdate(globalScope, multipleScriptsScope); newBlock.AddChunk(function); if (globalScope.ScriptHeader.BasicScriptType == TES5BasicType.T_QUEST) { TES5EventCodeBlock onInitBlock = TES5BlockFactory.CreateOnInit(); onInitBlock.AddChunk(function); blockList.Add(onInitBlock); } break; } case "onactivate": { TES5EventCodeBlock onInitBlock = TES5BlockFactory.CreateOnInit(); TES5ObjectCall function = this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToSelf(globalScope), "BlockActivation", multipleScriptsScope); onInitBlock.AddChunk(function); blockList.Add(onInitBlock); break; } case "onactorequip": { SetUpBranch(block, newBlock, blockFunctionScope, TES5LocalVariableParameterMeaning.CONTAINER, globalScope, multipleScriptsScope); break; } case "ontriggeractor": { TES4BlockParameterList parameterList = block.BlockParameterList; TES5LocalScope localScope = newBlock.CodeScope.LocalScope; TES5LocalVariable activator = localScope.GetVariableWithMeaning(TES5LocalVariableParameterMeaning.ACTIVATOR); TES5LocalVariable castedToActor = new TES5LocalVariable("akAsActor", TES5BasicType.T_ACTOR); TES5Reference referenceToCastedVariable = TES5ReferenceFactory.CreateReferenceToVariable(castedToActor); TES5Reference referenceToNonCastedVariable = TES5ReferenceFactory.CreateReferenceToVariable(activator); TES5ComparisonExpression expression = TES5ExpressionFactory.CreateComparisonExpression(referenceToCastedVariable, TES5ComparisonExpressionOperator.OPERATOR_NOT_EQUAL, new TES5None()); TES5CodeScope newCodeScope = TES5CodeScopeFactory.CreateCodeScopeRoot(blockFunctionScope); newCodeScope.LocalScope.AddVariable(castedToActor); newCodeScope.AddChunk(TES5VariableAssignationFactory.CreateAssignation(referenceToCastedVariable, referenceToNonCastedVariable)); TES5CodeScope outerBranchCode; if (parameterList != null) { //NOT TESTED List <TES4BlockParameter> parameterListVariableList = parameterList.Parameters; ITES5Referencer targetActor = this.referenceFactory.CreateReadReference(parameterListVariableList[0].BlockParameter, globalScope, multipleScriptsScope, localScope); TES5ComparisonExpression interExpression = TES5ExpressionFactory.CreateComparisonExpression(TES5ReferenceFactory.CreateReferenceToVariable(activator), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, targetActor); //TES5CodeScope interBranchCode = PHPFunction.Deserialize<TES5CodeScope>(PHPFunction.Serialize(newBlock.CodeScope));//WTM: Change: Why serialize and then deserialize? TES5CodeScope interBranchCode = newBlock.CodeScope; outerBranchCode = TES5CodeScopeFactory.CreateCodeScopeRoot(blockFunctionScope); interBranchCode.LocalScope.ParentScope = outerBranchCode.LocalScope; outerBranchCode.AddChunk(new TES5Branch(new TES5SubBranch(interExpression, interBranchCode))); } else { //outerBranchCode = PHPFunction.Deserialize<TES5CodeScope>(PHPFunction.Serialize(newBlock.CodeScope));//WTM: Change: Why serialize and then deserialize? outerBranchCode = newBlock.CodeScope; outerBranchCode.LocalScope.ParentScope = newCodeScope.LocalScope; } newCodeScope.AddChunk(new TES5Branch(new TES5SubBranch(expression, outerBranchCode))); newBlock.CodeScope = newCodeScope; break; } case "onadd": { SetUpBranch(block, newBlock, blockFunctionScope, "akNewContainer", globalScope, multipleScriptsScope); break; } case "ondrop": { SetUpBranch(block, newBlock, blockFunctionScope, "akOldContainer", globalScope, multipleScriptsScope); break; } case "onpackagestart": { SetUpBranch(block, newBlock, blockFunctionScope, "akNewPackage", globalScope, multipleScriptsScope); break; } case "onpackagedone": case "onpackagechange": case "onpackageend": { SetUpBranch(block, newBlock, blockFunctionScope, "akOldPackage", globalScope, multipleScriptsScope); break; } case "onalarm": { //@INCONSISTENCE - We don"t account for alarm type. TES5ComparisonExpression expression = TES5ExpressionFactory.CreateComparisonExpression(this.objectCallFactory.CreateObjectCall(TES5ReferenceFactory.CreateReferenceToSelf(globalScope), "IsAlarmed", multipleScriptsScope), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Bool(true)); SetUpBranch(blockFunctionScope, newBlock, expression); 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 "onequip": case "onunequip": { SetUpBranch(block, newBlock, blockFunctionScope, "akActor", globalScope, multipleScriptsScope); break; } } }
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 ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES5LocalScope localScope = codeScope.LocalScope; TES4FunctionArguments functionArguments = function.Arguments; ITES5Referencer argument = this.referenceFactory.CreateReadReference(functionArguments[0].StringValue, globalScope, multipleScriptsScope, localScope); TES5ComparisonExpression expression = TES5ExpressionFactory.CreateComparisonExpression(calledOn, TES5ComparisonExpressionOperator.OPERATOR_EQUAL, argument); return(expression); }
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES5LocalScope localScope = codeScope.LocalScope; TES4FunctionArguments functionArguments = function.Arguments; ITES5Referencer newCalledOn = this.referenceFactory.CreateReadReference(functionArguments[0].StringValue, globalScope, multipleScriptsScope, localScope); TES5ObjectCallArguments arguments = new TES5ObjectCallArguments(); TES5Bool force; if (functionArguments.Count == 1) { force = new TES5Bool(false); } else { force = new TES5Bool(((TES4Integer)functionArguments[1]).IntValue == 1); } arguments.Add(force); return(this.objectCallFactory.CreateObjectCall(newCalledOn, "ForceActive", multipleScriptsScope, arguments)); }
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES5LocalScope localScope = codeScope.LocalScope; //@INCONSISTENCE - Will only check for scripted effects //In oblivion, this is checking for a spell which targeted a given actor //In Skyrim you can check for effects only. TES5ObjectCallArguments newArgs = new TES5ObjectCallArguments() { this.referenceFactory.CreateReference("EffectSEFF", TES5BasicType.T_MAGICEFFECT, globalScope, multipleScriptsScope, localScope) }; return(this.objectCallFactory.CreateObjectCall(calledOn, "HasMagicEffect", newArgs)); }
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES4FunctionArguments functionArguments = function.Arguments; TES5LocalScope localScope = codeScope.LocalScope; ITES5Referencer newCalledOn = this.referenceFactory.CreateReadReference(functionArguments.Pop(0).StringValue, globalScope, multipleScriptsScope, localScope); const string functionName = "AddToMap"; return(this.objectCallFactory.CreateObjectCall(newCalledOn, functionName, this.objectCallArgumentsFactory.CreateArgumentList(functionArguments, codeScope, globalScope, multipleScriptsScope))); }
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) { const string functionName = "playGamebryoAnimation"; TES4FunctionArguments functionArguments = function.Arguments; //this function does not use strings for the names, so i cant really understand what is it. //todo refactor TES5ObjectCallArguments convertedArguments = new TES5ObjectCallArguments(); ITES4StringValue firstArg = functionArguments[0]; convertedArguments.Add(new TES5String(firstArg.StringValue)); /* * secondArg = functionArguments.getValue(1); * * if (secondArg && secondArg.getData() != 0) { * convertedArguments.add(new TES5Integer(1)); * }*/ convertedArguments.Add(new TES5Bool(true)); return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, convertedArguments)); }
private void SetUpBranch(TES4CodeBlock block, TES5EventCodeBlock newBlock, TES5FunctionScope blockFunctionScope, TES5LocalVariableParameterMeaning variable, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { SetUpBranch(block, newBlock, blockFunctionScope, newBlock.CodeScope.LocalScope.GetVariableWithMeaning(variable), globalScope, multipleScriptsScope); }
public abstract ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope);
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES4FunctionArguments functionArguments = function.Arguments; string functionName = function.FunctionCall.FunctionName; TES5ObjectCallArguments methodArguments = new TES5ObjectCallArguments() { new TES5Bool(true)//override different behaviour }; ITES4StringValue lockAsOwnerBool = functionArguments.GetOrNull(1); bool newLockBool = lockAsOwnerBool != null && (int)lockAsOwnerBool.Data == 1; methodArguments.Add(new TES5Bool(newLockBool)); return(this.objectCallFactory.CreateObjectCall(calledOn, functionName, multipleScriptsScope, methodArguments)); }
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES4FunctionArguments functionArguments = function.Arguments; TES5ObjectCall functionThis = this.objectCallFactory.CreateObjectCall(this.objectCallFactory.CreateGetActorBase(calledOn, multipleScriptsScope), "GetSex", multipleScriptsScope); int operand; switch ((functionArguments[0].StringValue).ToLower()) { case "male": { operand = 0; break; } case "female": { operand = 1; break; } default: { throw new ConversionException("GetIsSex used with unknown gender."); } } TES5ComparisonExpression expression = TES5ExpressionFactory.CreateComparisonExpression(functionThis, TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Integer(operand)); return(expression); }
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES5LocalScope localScope = codeScope.LocalScope; return(this.referenceFactory.CreateReadReference(TES5ReferenceFactory.MESSAGEBOX_VARIABLE_CONST, globalScope, multipleScriptsScope, localScope)); }
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { const string functionName = "QueryStat"; ITES5Referencer newCalledOn = TES5StaticReferenceFactory.Game; TES4FunctionArguments functionArguments = function.Arguments; int oldArgValue = (int)functionArguments.Single().Data; string newArgValue = statMap[oldArgValue]; TES4FunctionArguments tes4Arguments = new TES4FunctionArguments() { new TES4String(newArgValue) }; TES5ObjectCallArguments tes5Arguments = objectCallArgumentsFactory.CreateArgumentList(tes4Arguments, codeScope, globalScope, multipleScriptsScope); return(objectCallFactory.CreateObjectCall(newCalledOn, functionName, tes5Arguments)); }