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); }
private TES5CodeScope ConvertTES4CodeChunksToTES5CodeScope(TES4CodeChunks chunks, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES5CodeScope newCodeScope = TES5CodeScopeFactory.CreateCodeScope(codeScope.LocalScope); foreach (ITES4CodeChunk codeChunk in chunks) { TES5CodeChunkCollection codeChunks = this.codeChunkFactory.CreateCodeChunk(codeChunk, codeScope, globalScope, multipleScriptsScope); newCodeScope.AddChunk(codeChunks); } return(newCodeScope); }
public TES5CodeChunkCollection CreateCodeChunkCollection(TES5FunctionScope functionScope, TES5GlobalScope globalScope) { TES5CodeChunkCollection collection = new TES5CodeChunkCollection(); if (functionScope.BlockName == "OnUpdate") { TES5ObjectCall function = this.objectCallFactory.CreateRegisterForSingleUpdate(globalScope); collection.Add(function); } collection.Add(new TES5Return()); return(collection); }
public TES5FunctionCodeBlock CreateFragment(TES5FragmentType fragmentType, string fragmentName, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope, TES4CodeChunks chunks) { TES5FunctionScope fragmentLocalScope = TES5FragmentFunctionScopeFactory.CreateFromFragmentType(fragmentName, fragmentType); TES5FunctionCodeBlock function = new TES5FunctionCodeBlock(fragmentLocalScope, TES5CodeScopeFactory.CreateCodeScopeRoot(fragmentLocalScope), TES5VoidType.Instance, false, fragmentType == TES5FragmentType.T_QF || fragmentType == TES5FragmentType.T_TIF); foreach (var codeChunk in chunks) { TES5CodeChunkCollection codeChunks = this.codeChunkFactory.CreateCodeChunk(codeChunk, function.CodeScope, globalScope, multipleScriptsScope); foreach (var newCodeChunk in codeChunks) { function.AddChunk(newCodeChunk); } } return(function); }
public ITES5ValueCodeChunk CreateLogCall(TES4Function function, string?reason = null) { string message = "OBScript called " + function.FunctionCall.FunctionName + "(" + string.Join(", ", function.Arguments.Select(a => a.StringValue)) + "), but script converter didn't know a conversion." + (reason != null ? " " + reason : ""); TES5CodeChunkCollection codeChunks = new TES5CodeChunkCollection(); TES5ObjectCallArguments arguments = new TES5ObjectCallArguments() { new TES5String(message) }; codeChunks.Add(objectCallFactory.CreateObjectCall(TES5StaticReferenceFactory.Debug, "Trace", arguments)); #if UNKNOWN_FUNCTIONS_MESSAGE_BOX codeChunks.Add(objectCallFactory.CreateObjectCall(TES5StaticReferenceFactory.Debug, "MessageBox", arguments));//Debug.Notification might be a useful alternative. #endif return(codeChunks); }
private void ConvertTES4CodeChunksToTES5EventCodeBlock(TES4CodeChunks chunks, TES5EventCodeBlock newBlock, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES5CodeScope conversionScope = this.initialBlockCodeFactory.AddInitialCode(multipleScriptsScope, globalScope, newBlock); foreach (ITES4CodeChunk codeChunk in chunks) { TES5CodeChunkCollection codeChunks = this.codeChunkFactory.createCodeChunk(codeChunk, newBlock.CodeScope, globalScope, multipleScriptsScope); if (codeChunks != null) { foreach (ITES5CodeChunk newCodeChunk in codeChunks) { conversionScope.AddChunk(newCodeChunk); } } } }
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES4FunctionArguments functionArguments = function.Arguments; TES5CodeChunkCollection codeChunks = new TES5CodeChunkCollection(); if (functionArguments.Any()) { int oblivionLockLevel = (int)functionArguments[0].Data; int skyrimLockLevel; if (oblivionLockLevel == 0) { skyrimLockLevel = 1; } else if (oblivionLockLevel > 0 && oblivionLockLevel < 99) { skyrimLockLevel = oblivionLockLevel; } else if (oblivionLockLevel == 99) { skyrimLockLevel = 100; } else if (oblivionLockLevel == 100) { skyrimLockLevel = 255; } else { throw new ConversionException("Oblivion lock level out of range (0-100): " + oblivionLockLevel); } TES5ObjectCallArguments setLockLevelArguments = new TES5ObjectCallArguments() { new TES5Integer(skyrimLockLevel) }; codeChunks.Add(this.objectCallFactory.CreateObjectCall(calledOn, "SetLockLevel", setLockLevelArguments)); } ITES4StringValue? lockAsOwnerBool = functionArguments.GetOrNull(1); TES5ObjectCallArguments lockArguments = new TES5ObjectCallArguments() { new TES5Bool(true), //abLock new TES5Bool(lockAsOwnerBool != null && (int)lockAsOwnerBool.Data == 1) //abAsOwner }; codeChunks.Add(this.objectCallFactory.CreateObjectCall(calledOn, "Lock", lockArguments)); return(codeChunks); }
private static TES5ElseSubBranch ConvertElseBranch(TES4ElseSubBranch branch, TES5CodeScope outerCodeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope, TES5ChainedCodeChunkFactory codeChunkFactory) { TES5CodeScope newCodeScope = TES5CodeScopeFactory.CreateCodeScopeRecursive(outerCodeScope.LocalScope); TES4CodeChunks?branchChunks = branch.CodeChunks; if (branchChunks != null) { foreach (ITES4CodeChunk codeChunk in branchChunks) { TES5CodeChunkCollection codeChunks = codeChunkFactory.CreateCodeChunk(codeChunk, newCodeScope, globalScope, multipleScriptsScope); foreach (ITES5CodeChunk newCodeChunk in codeChunks) { newCodeScope.AddChunk(newCodeChunk); } } } return(new TES5ElseSubBranch(newCodeScope)); }
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { //WTM: @Inconsistence: //SKSE has Game.SetPlayerLevel(int level), but Oblivion calls this function on non-player actors. //Since we can't call SetLevel directly, we are instead modifying actor values. TES4FunctionArguments tes4Arguments = function.Arguments; int newLevel = (int)tes4Arguments[0].Data; bool levelToPC = tes4Arguments.Count > 1 ? (int)tes4Arguments[1].Data == 1 : false;//When false, newLevel should be evaluated absolutely. When true, newLevel should be evaluated relative to the current level. string newFunctionName = !levelToPC ? "SetActorValue" : "ModActorValue"; int attributeLevel = newLevel, skillLevel = newLevel; const int minAttributeValue = 25, minSkillLevel = 10; if (levelToPC) {//If levelToPC is true, increase or decrease attributes 10 times greater than the level change and skills 2 times greater than the level change. attributeLevel *= 10; skillLevel *= 2; } else {//If levelToPC is false, ensure values are not set to values less than minimums. if (attributeLevel < minAttributeValue) { attributeLevel = minAttributeValue; } if (skillLevel < minSkillLevel) { skillLevel = minSkillLevel; } } TES5CodeChunkCollection codeChunks = new TES5CodeChunkCollection(); string[] attributes = new string[] { "Health", "Magicka", "Stamina" }; codeChunks.AddRange(attributes.Select(a => objectCallFactory.CreateObjectCall(calledOn, newFunctionName, multipleScriptsScope, new TES5ObjectCallArguments() { new TES5String(a), new TES5Float(attributeLevel) }))); string[] skills = new string[] { "OneHanded", "TwoHanded", "Marksman", "Block", "Smithing", "HeavyArmor", "LightArmor", "Pickpocket", "Lockpicking", "Sneak", "Alchemy", "Speechcraft", "Alteration", "Conjuration", "Destruction", "Illusion", "Restoration", "Enchanting" }; codeChunks.AddRange(skills.Select(s => objectCallFactory.CreateObjectCall(calledOn, newFunctionName, multipleScriptsScope, new TES5ObjectCallArguments() { new TES5String(s), new TES5Float(skillLevel) }))); return(codeChunks); }
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES5LocalScope localScope = codeScope.LocalScope; TES4FunctionArguments functionArguments = function.Arguments; string questName = functionArguments.Pop(0).StringValue; ITES5Referencer newCalledOn = this.referenceFactory.CreateReadReference(questName, globalScope, multipleScriptsScope, localScope); /* * Basically, there are some ugly mechanics in Oblivion. * Two quests ( FGInterimConversation and Arena* quest group ) are repeadetely started and stopped * However, Skyrim does not support this - once 0x13A byte is marked in a TESQuest, it won"t allow * to be started again. Hence, we need to call a Papyrus endpoint to stop the quest and * reset this field, and be able to reset the quest completely. */ TES5CodeChunkCollection codeChunks = new TES5CodeChunkCollection(); codeChunks.Add(this.objectCallFactory.CreateObjectCall(newCalledOn, "Stop", this.objectCallArgumentsFactory.CreateArgumentList(functionArguments, codeScope, globalScope, multipleScriptsScope))); if (questName == "FGInterimConversation" || questName == "ArenaIC" || questName == "ArenaICGrandChampion" || questName == "ArenaAggression" || questName == "ArenaAnnouncer" || questName == "ArenaDisqualification" || questName == "Arena") { codeChunks.Add(this.objectCallFactory.CreateObjectCall(newCalledOn, "PrepareForReinitializing", new TES5ObjectCallArguments())); } return(codeChunks); }
private static TES5SubBranch ConvertSubBranch(TES4SubBranch branch, TES5CodeScope outerCodeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope, TES5ChainedCodeChunkFactory codeChunkFactory, TES5ValueFactory valueFactory) { ITES5Value expression = valueFactory.CreateValue(branch.Expression, outerCodeScope, globalScope, multipleScriptsScope); TES5CodeScope newCodeScope = TES5CodeScopeFactory.CreateCodeScopeRecursive(outerCodeScope.LocalScope); TES4CodeChunks branchChunks = branch.CodeChunks; if (branchChunks != null) { foreach (ITES4CodeChunk codeChunk in branchChunks) { TES5CodeChunkCollection codeChunks = codeChunkFactory.createCodeChunk(codeChunk, newCodeScope, globalScope, multipleScriptsScope); if (codeChunks != null) { foreach (ITES5CodeChunk newCodeChunk in codeChunks) { newCodeScope.AddChunk(newCodeChunk); } } } } return(new TES5SubBranch(expression, newCodeScope)); }