public static void GenerateINFOAddTopicScripts(ESMAnalyzer esmAnalyzer, BuildTracker buildTracker, IBuildTarget tifBuildTarget) { TES5TypeInferencer typeInferencer = new TES5TypeInferencer(esmAnalyzer); TES5ObjectCallFactory objectCallFactory = new TES5ObjectCallFactory(typeInferencer); TES4TopicsToTES5GlobalVariableFinder globalVariableFinder = new TES4TopicsToTES5GlobalVariableFinder(); TES5GlobalVariables globalVariables = esmAnalyzer.GlobalVariables; var builtTIFs = buildTracker.GetBuiltScripts(BuildTargetFactory.TIFName); foreach (TES4Record infoRecord in esmAnalyzer.GetRecords().Where(r => r.RecordType == TES4RecordType.INFO)) { TES4SubrecordData[] names = infoRecord.GetSubrecords("NAME").ToArray(); if (names.Any()) { string fragment0Name = TES5FragmentFactory.GetFragmentName(0); string nameTES5FormIDHex = (infoRecord.FormID + 0x01000000).ToString("x8"); string scriptName = TES5ReferenceFactory.tif_Prefix + "_" + nameTES5FormIDHex; TES5Script? infoTIF = builtTIFs.Where(s => s.Key == scriptName).Select(s => s.Value.Script).FirstOrDefault(); TES5FunctionCodeBlock fragment0; if (infoTIF != null) { fragment0 = infoTIF.BlockList.Blocks.OfType <TES5FunctionCodeBlock>().Where(b => b.BlockName == fragment0Name).First(); } else { TES5ScriptHeader scriptHeader = TES5ScriptHeaderFactory.GetFromCacheOrConstructByBasicType(scriptName, TES5BasicType.T_TOPICINFO, TES5TypeFactory.TES4_Prefix, true); TES5GlobalScope globalScope = new TES5GlobalScope(scriptHeader); TES5FunctionScope functionScope = new TES5FunctionScope(fragment0Name); functionScope.AddParameter(new TES5SignatureParameter("akSpeakerRef", TES5BasicType.T_OBJECTREFERENCE, true)); TES5LocalScope localScope = new TES5LocalScope(functionScope); TES5CodeScope codeScope = TES5CodeScopeFactory.CreateCodeScope(localScope); fragment0 = new TES5FunctionCodeBlock(functionScope, codeScope, TES5VoidType.Instance, false, true); TES5BlockList blockList = new TES5BlockList() { fragment0 }; infoTIF = new TES5Script(globalScope, blockList, true); string outputPath = tifBuildTarget.GetTranspileToPath(scriptName); TES5Target target = new TES5Target(infoTIF, outputPath); buildTracker.RegisterBuiltScript(tifBuildTarget, target); } foreach (TES4SubrecordData name in names) { int formID = infoRecord.ExpandBytesIntoFormID(name); TES4Record addedTopic = esmAnalyzer.GetRecordByFormID(formID); Tuple <int, string>?globalVariable = globalVariableFinder.GetGlobalVariableNullable(addedTopic.FormID); string globalVariableEditorID = globalVariable != null ? globalVariable.Item2 : globalVariableFinder.GetGlobalVariableEditorID(addedTopic.GetEditorID()); Nullable <int> globalVariableTES5FormID = globalVariable != null ? globalVariable.Item1 : (Nullable <int>)null; TES5Property topicAddedProperty = TES5PropertyFactory.ConstructWithTES5FormID(globalVariableEditorID, TES5BasicType.T_GLOBALVARIABLE, globalVariableEditorID, globalVariableTES5FormID); infoTIF.GlobalScope.AddPropertyIfNotExists(topicAddedProperty); TES5Reference topicAddedReference = TES5ReferenceFactory.CreateReferenceToVariableOrProperty(topicAddedProperty); fragment0.AddChunk(objectCallFactory.CreateObjectCall(topicAddedReference, "SetValueInt", new TES5ObjectCallArguments() { new TES5Integer(1) })); } } } }
public List <ITES5CodeChunk> GenerateObjectiveHandling(ITES5CodeBlock codeBlock, TES5GlobalScope globalScope, List <int> stageMap) { TES5LocalVariable castedToQuest = new TES5LocalVariable("__temp", TES5BasicType.T_QUEST); TES5Reference referenceToTemp = TES5ReferenceFactory.CreateReferenceToVariable(castedToQuest); List <ITES5CodeChunk> result = new List <ITES5CodeChunk>() { TES5VariableAssignationFactory.CreateAssignation(referenceToTemp, TES5ReferenceFactory.CreateReferenceToSelf(globalScope)) }; TES5LocalScope localScope = codeBlock.CodeScope.LocalScope; localScope.AddVariable(castedToQuest); int i = 0; foreach (var stageTargetState in stageMap) { TES5Integer targetIndex = new TES5Integer(i); if (stageTargetState != 0) { //Should be visible TES5ObjectCallArguments displayedArguments = new TES5ObjectCallArguments() { targetIndex }; TES5ObjectCall isObjectiveDisplayed = new TES5ObjectCall(referenceToTemp, "IsObjectiveDisplayed", displayedArguments); TES5ComparisonExpression expression = TES5ExpressionFactory.CreateComparisonExpression(isObjectiveDisplayed, TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Integer(0)); TES5ObjectCallArguments arguments = new TES5ObjectCallArguments() { targetIndex, new TES5Integer(1) }; TES5ObjectCall showTheObjective = new TES5ObjectCall(referenceToTemp, "SetObjectiveDisplayed", arguments); TES5Branch branch = TES5BranchFactory.CreateSimpleBranch(expression, localScope); branch.MainBranch.CodeScope.AddChunk(showTheObjective); result.Add(branch); } else { TES5ObjectCallArguments displayedArguments = new TES5ObjectCallArguments() { targetIndex }; TES5ObjectCall isObjectiveDisplayed = new TES5ObjectCall(referenceToTemp, "IsObjectiveDisplayed", displayedArguments); TES5ComparisonExpression expression = TES5ExpressionFactory.CreateComparisonExpression(isObjectiveDisplayed, TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Integer(1)); TES5ObjectCallArguments arguments = new TES5ObjectCallArguments() { targetIndex, new TES5Integer(1) }; TES5ObjectCall completeTheObjective = new TES5ObjectCall(referenceToTemp, "SetObjectiveCompleted", arguments); TES5Branch branch = TES5BranchFactory.CreateSimpleBranch(expression, localScope); branch.MainBranch.CodeScope.AddChunk(completeTheObjective); result.Add(branch); } ++i; } return(result); }
private TES5FunctionCodeBlock GetGetArmorRatingOfWornFormFunctionCodeBlock(ITES5Referencer calledOn, TES5CodeScope codeScope) { TES5FunctionCodeBlock functionCodeBlock = new TES5FunctionCodeBlock(new TES5FunctionScope(functionName), TES5CodeScopeFactory.CreateCodeScope(codeScope.LocalScope), TES5BasicType.T_INT, false, false); TES5SignatureParameter slotMaskParameter = new TES5SignatureParameter("slotMask", TES5BasicType.T_INT, true); functionCodeBlock.FunctionScope.AddParameter(slotMaskParameter); TES5ObjectCall getWornForm = GetGetWornFormObjectCall(calledOn, TES5ReferenceFactory.CreateReferenceToVariableOrProperty(slotMaskParameter)); TES5LocalVariable wornFormVariable = new TES5LocalVariable("wornForm", TES5BasicType.T_ARMOR); functionCodeBlock.CodeScope.AddVariable(wornFormVariable); TES5Reference wornFormVariableReference = TES5ReferenceFactory.CreateReferenceToVariableOrProperty(wornFormVariable); functionCodeBlock.AddChunk(TES5VariableAssignationFactory.CreateAssignation(wornFormVariableReference, getWornForm)); functionCodeBlock.AddChunk(new TES5Return(objectCallFactory.CreateObjectCall(wornFormVariableReference, "GetArmorRating"))); return(functionCodeBlock); }
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 ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { ITES5Referencer topic = referenceFactory.CreateReference(function.Arguments[0].StringValue, globalScope, multipleScriptsScope, codeScope.LocalScope); TES5Property property = (TES5Property)topic.ReferencesTo !; Tuple <int, string>?newGlobalVariable; if (globalVariableFinder.TryGetGlobalVariable(property.TES4FormID !.Value, out newGlobalVariable)) { TES5Property globalVariableProperty = TES5PropertyFactory.ConstructWithTES5FormID(newGlobalVariable.Item2, TES5BasicType.T_GLOBALVARIABLE, newGlobalVariable.Item2, newGlobalVariable.Item1); globalScope.AddPropertyIfNotExists(globalVariableProperty); TES5Reference globalVariableReference = TES5ReferenceFactory.CreateReferenceToVariableOrProperty(globalVariableProperty); return(objectCallFactory.CreateObjectCall(globalVariableReference, "SetValueInt", new TES5ObjectCallArguments() { new TES5Integer(1) })); } return(popCalledRenameFunctionFactory.ConvertFunction(calledOn, function, codeScope, globalScope, multipleScriptsScope)); }
public ITES5ValueCodeChunk ConvertFunction(ITES5Referencer calledOn, TES4Function function, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { TES4FunctionArguments functionArguments = function.Arguments; ITES4StringValue apiToken = functionArguments[0]; string cellEditorID = apiToken.StringValue; string locationPropertyNameWithoutSuffix = cellEditorID + "Location"; string locationPropertyNameWithSuffix = TES5Property.AddPropertyNameSuffix(locationPropertyNameWithoutSuffix); TES5Property?locationProperty = globalScope.TryGetPropertyByName(locationPropertyNameWithSuffix); if (locationProperty == null) { int tes5LocationFormID; if (cellToLocationFinder.TryGetLocationFormID(cellEditorID, out tes5LocationFormID)) { locationProperty = TES5PropertyFactory.ConstructWithTES5FormID(locationPropertyNameWithoutSuffix, TES5BasicType.T_LOCATION, null, tes5LocationFormID); globalScope.AddProperty(locationProperty); } else { TES5ObjectCall getParentCell = this.objectCallFactory.CreateObjectCall(calledOn, "GetParentCell"); TES5ObjectCall getParentCellName = this.objectCallFactory.CreateObjectCall(getParentCell, "GetName"); TES4Record cellRecord = this.esmAnalyzer.GetRecordByEDIDInTES4Collection(cellEditorID); string? cellNameWithSpaces = cellRecord.TryGetSubrecordTrim("FULL"); if (cellNameWithSpaces == null || cellNameWithSpaces.IndexOf("Dummy", StringComparison.OrdinalIgnoreCase) != -1) { cellNameWithSpaces = cellEditorID; } TES5String cellNameTES5String = new TES5String(cellNameWithSpaces); TES5ObjectCallArguments findArguments = new TES5ObjectCallArguments() { getParentCellName, cellNameTES5String }; TES5ObjectCall substring = this.objectCallFactory.CreateObjectCall(TES5StaticReferenceFactory.StringUtil, "Find", findArguments); return(TES5ExpressionFactory.CreateComparisonExpression(substring, TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Integer(0))); } } TES5Reference locationReference = TES5ReferenceFactory.CreateReferenceToVariableOrProperty(locationProperty); return(this.objectCallFactory.CreateObjectCall(calledOn, "IsInLocation", new TES5ObjectCallArguments() { locationReference })); }
public List <ITES5CodeChunk> GenerateObjectiveHandling(ITES5CodeBlock codeBlock, TES5GlobalScope globalScope, List <int> stageMap) { List <ITES5CodeChunk> result = new List <ITES5CodeChunk>(); //WTM: Change: if (!stageMap.Any()) { return(result); } TES5LocalVariable castedToQuest = new TES5LocalVariable("__temp", TES5BasicType.T_QUEST);//WTM: Note: Why is this variable even necessary? TES5Reference referenceToTemp = TES5ReferenceFactory.CreateReferenceToVariableOrProperty(castedToQuest); TES5SelfReference questSelfReference = TES5ReferenceFactory.CreateReferenceToSelf(globalScope); TES5VariableAssignation tempQuestAssignation = TES5VariableAssignationFactory.CreateAssignation(referenceToTemp, questSelfReference); result.Add(tempQuestAssignation); TES5LocalScope localScope = codeBlock.CodeScope.LocalScope; localScope.AddVariable(castedToQuest); int i = 0; foreach (var stageTargetState in stageMap) { TES5Integer targetIndex = new TES5Integer(i); TES5ObjectCallArguments displayedArguments = new TES5ObjectCallArguments() { targetIndex }; TES5ObjectCall isObjectiveDisplayed = objectCallFactory.CreateObjectCall(referenceToTemp, "IsObjectiveDisplayed", displayedArguments, inference: false); int isObjectiveDisplayedArgument = stageTargetState != 0 ? 0 : 1; TES5ComparisonExpression expression = TES5ExpressionFactory.CreateComparisonExpression(isObjectiveDisplayed, TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Integer(isObjectiveDisplayedArgument)); TES5ObjectCallArguments arguments = new TES5ObjectCallArguments() { targetIndex, new TES5Integer(1) }; string setObjectiveFunction = stageTargetState != 0 ? "SetObjectiveDisplayed" : "SetObjectiveCompleted"; TES5ObjectCall setObjectiveObjectCall = objectCallFactory.CreateObjectCall(referenceToTemp, setObjectiveFunction, arguments, inference: false); TES5Branch branch = TES5BranchFactory.CreateSimpleBranch(expression, localScope); branch.MainBranch.CodeScope.AddChunk(setObjectiveObjectCall); result.Add(branch); ++i; } return(result); }
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; } } }
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); }
private ITES5Value ConvertComparisonExpression(ITES4BinaryExpression expression, TES5CodeScope codeScope, TES5GlobalScope globalScope, TES5MultipleScriptsScope multipleScriptsScope) { Tuple <ITES4Value, ITES4Value>[] tes4ValueTuples = new Tuple <ITES4Value, ITES4Value>[] { new Tuple <ITES4Value, ITES4Value>(expression.LeftValue, expression.RightValue), new Tuple <ITES4Value, ITES4Value>(expression.RightValue, expression.LeftValue) }; /* * Scenario 1 - Special functions converted on expression level */ foreach (Tuple <ITES4Value, ITES4Value> tes4ValueTuple in tes4ValueTuples) { ITES4Callable?valueTupleItem1 = tes4ValueTuple.Item1 as ITES4Callable; if (valueTupleItem1 == null) { continue; } TES4Function function = valueTupleItem1.Function; switch (function.FunctionCall.FunctionName.ToLower()) { case "getweaponanimtype": { ITES5Referencer calledOn = this.CreateCalledOnReferenceOfCalledFunction(valueTupleItem1, codeScope, globalScope, multipleScriptsScope); TES5ObjectCall equippedWeaponLeftValue = this.objectCallFactory.CreateObjectCall(this.objectCallFactory.CreateObjectCall(calledOn, "GetEquippedWeapon"), "GetWeaponType"); int[] targetedWeaponTypes; switch ((int)tes4ValueTuple.Item2.Data) { case 0: { targetedWeaponTypes = new int[] { 0 }; break; } case 1: { targetedWeaponTypes = new int[] { 1, 2, 3, 4 }; break; } case 2: { targetedWeaponTypes = new int[] { 5, 6, 8 }; break; } case 3: { targetedWeaponTypes = new int[] { 7, 9 }; break; } default: { throw new ConversionException("GetWeaponAnimType() - Unknown weapon type in expression"); } } List <TES5ComparisonExpression> expressions = new List <TES5ComparisonExpression>(); foreach (var targetedWeaponType in targetedWeaponTypes) { expressions.Add(TES5ExpressionFactory.CreateComparisonExpression(equippedWeaponLeftValue, TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Integer(targetedWeaponType))); } ITES5Expression resultExpression = expressions[0]; expressions.RemoveAt(0); while (expressions.Any()) { resultExpression = TES5ExpressionFactory.CreateLogicalExpression(resultExpression, TES5LogicalExpressionOperator.OPERATOR_OR, expressions.Last()); expressions.RemoveAt(expressions.Count - 1); } return(resultExpression); } case "getdetected": { TES5ObjectCallArguments inversedArgument = new TES5ObjectCallArguments() { this.CreateCalledOnReferenceOfCalledFunction(valueTupleItem1, codeScope, globalScope, multipleScriptsScope) }; TES5ObjectCall getDetectedLeftValue = this.objectCallFactory.CreateObjectCall(this.referenceFactory.CreateReadReference(function.Arguments[0].StringValue, globalScope, multipleScriptsScope, codeScope.LocalScope), "isDetectedBy", inversedArgument); TES5Integer getDetectedRightValue = new TES5Integer(((int)tes4ValueTuple.Item2.Data == 0) ? 0 : 1); return(TES5ExpressionFactory.CreateComparisonExpression(getDetectedLeftValue, TES5ComparisonExpressionOperator.OPERATOR_EQUAL, getDetectedRightValue)); } case "getdetectionlevel": { if (!tes4ValueTuple.Item2.HasFixedValue) { throw new ConversionException("Cannot convert getDetectionLevel calls with dynamic comparision"); } TES5Bool tes5Bool = new TES5Bool(((int)tes4ValueTuple.Item2.Data) == 3); //true only if the compared value was 3 TES5ObjectCallArguments inversedArgument = new TES5ObjectCallArguments() { this.CreateCalledOnReferenceOfCalledFunction(valueTupleItem1, codeScope, globalScope, multipleScriptsScope) }; return(TES5ExpressionFactory.CreateComparisonExpression ( this.objectCallFactory.CreateObjectCall(this.referenceFactory.CreateReadReference(function.Arguments[0].StringValue, globalScope, multipleScriptsScope, codeScope.LocalScope), "isDetectedBy", inversedArgument), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, tes5Bool )); } case "getcurrentaiprocedure": { if (!tes4ValueTuple.Item2.HasFixedValue) { throw new ConversionException("Cannot convert getCurrentAIProcedure() calls with dynamic comparision"); } switch ((int)tes4ValueTuple.Item2.Data) { case 4: { return(TES5ExpressionFactory.CreateComparisonExpression( this.objectCallFactory.CreateObjectCall(this.CreateCalledOnReferenceOfCalledFunction(valueTupleItem1, codeScope, globalScope, multipleScriptsScope), "IsInDialogueWithPlayer"), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Bool(expression.Operator == TES4ComparisonExpressionOperator.OPERATOR_EQUAL) //cast to true if the original op was ==, false otherwise. )); } case 8: { //ref.getSleepState() == 3 return(TES5ExpressionFactory.CreateComparisonExpression( this.objectCallFactory.CreateObjectCall(this.CreateCalledOnReferenceOfCalledFunction(valueTupleItem1, codeScope, globalScope, multipleScriptsScope), "getSleepState"), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Integer(3) //SLEEPSTATE_SLEEP )); } case 13: { return(TES5ExpressionFactory.CreateComparisonExpression( this.objectCallFactory.CreateObjectCall(this.CreateCalledOnReferenceOfCalledFunction(valueTupleItem1, codeScope, globalScope, multipleScriptsScope), "IsInCombat"), TES5ComparisonExpressionOperator.OPERATOR_EQUAL, new TES5Bool(expression.Operator == TES4ComparisonExpressionOperator.OPERATOR_EQUAL) //cast to true if the original op was ==, false otherwise. )); } case 0: //Travel case 7: //Wander case 15: //Pursue case 17: //Done { //@INCONSISTENCE idk how to check it tbh. We return always true. Think about better representation return(new TES5Bool(expression.Operator == TES4ComparisonExpressionOperator.OPERATOR_EQUAL)); } default: { throw new ConversionException("Cannot convert GetCurrentAiProcedure - unknown TES4 procedure number arg " + ((int)tes4ValueTuple.Item2.Data).ToString()); } } } case "isidleplaying": case "getknockedstate": case "gettalkedtopc": { return(new TES5Bool(true)); //This is so unimportant that i think it"s not worth to find a good alternative and waste time. } case "getsitting": { //WARNING: Needs to implement Horse sittings, too. //SEE: http://www.gameskyrim.com/papyrus-isridinghorse-function-t255012.html int goTo; switch ((int)tes4ValueTuple.Item2.Data) { case 0: { goTo = 0; break; } case 1: case 2: case 11: case 12: { goTo = 2; break; } case 3: case 13: { goTo = 3; break; } case 4: case 14: { goTo = 4; break; } default: { throw new ConversionException("GetSitting - unknown state found"); } } //ref.getSleepState() == 3 return(TES5ExpressionFactory.CreateComparisonExpression ( this.objectCallFactory.CreateObjectCall(this.CreateCalledOnReferenceOfCalledFunction(valueTupleItem1, codeScope, globalScope, multipleScriptsScope), "GetSitState"), TES5ComparisonExpressionOperator.GetFirst(expression.Operator.Name), new TES5Integer(goTo) )); } } } ITES5Value leftValue = this.CreateValue(expression.LeftValue, codeScope, globalScope, multipleScriptsScope); ITES5Value rightValue = this.CreateValue(expression.RightValue, codeScope, globalScope, multipleScriptsScope); Tuple <ITES5Value, ITES5Value>[] tes5ValueTuples = new Tuple <ITES5Value, ITES5Value>[] { new Tuple <ITES5Value, ITES5Value>(leftValue, rightValue), new Tuple <ITES5Value, ITES5Value>(rightValue, leftValue) }; TES5BasicType objectReferenceType = TES5BasicType.T_FORM; //used just to make sure. TES5ComparisonExpressionOperator op = TES5ComparisonExpressionOperator.GetFirst(expression.Operator.Name); /* * Scenario 2: Comparision of ObjectReferences to integers ( quick formid check ) */ bool flipOperator = false; foreach (var valueTuple in tes5ValueTuples) { TES5ComparisonExpressionOperator newOp = !flipOperator ? op : op.Flip(); if (TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(valueTuple.Item1.TES5Type, objectReferenceType) || TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(valueTuple.Item1.TES5Type.NativeType, objectReferenceType)) { if (valueTuple.Item2.TES5Type == TES5BasicType.T_INT) { //Perhaps we should allow to try to cast upwards for primitives, .asPrimitive() or similar //In case we do know at compile time that we"re comparing against zero, then we can assume //we can compare against None, which allows us not call GetFormID() on most probably None object TES5Integer tes5SetItem2Integer = (TES5Integer)valueTuple.Item2; if (tes5SetItem2Integer.IntValue == 0) { newOp = op == TES5ComparisonExpressionOperator.OPERATOR_EQUAL ? op : TES5ComparisonExpressionOperator.OPERATOR_NOT_EQUAL; return(TES5ExpressionFactory.CreateComparisonExpression(valueTuple.Item1, newOp, new TES5None())); } else { ITES5Referencer callable = (ITES5Referencer)valueTuple.Item1; TES5ObjectCall tes5setNewItem1 = this.objectCallFactory.CreateObjectCall(callable, "GetFormID"); return(TES5ExpressionFactory.CreateComparisonExpression(tes5setNewItem1, newOp, valueTuple.Item2)); } } } else if (valueTuple.Item1.TES5Type.OriginalName == TES5VoidType.OriginalNameConst) { #if PHP_COMPAT TES5IntegerOrFloat tes5SetItem2Number = tes5set.Item2 as TES5IntegerOrFloat; if (tes5SetItem2Number != null && tes5SetItem2Number.ConvertedIntValue == 0) { return(TES5ExpressionFactory.createArithmeticExpression(tes5set.Item1, newOp, new TES5None())); } #else throw new ConversionException("Type was void.");//This shouldn't happen anymore. #endif } if (!TES5InheritanceGraphAnalyzer.IsTypeOrExtendsTypeOrIsNumberType(valueTuple.Item1.TES5Type, valueTuple.Item2.TES5Type, true))//WTM: Change: Added entire if branch { if (valueTuple.Item1.TES5Type.NativeType == TES5BasicType.T_QUEST && valueTuple.Item2.TES5Type == TES5BasicType.T_INT) { TES5ObjectCall getStage = this.objectCallFactory.CreateObjectCall((ITES5Referencer)valueTuple.Item1, "GetStage"); return(TES5ExpressionFactory.CreateComparisonExpression(getStage, newOp, valueTuple.Item2)); } if (valueTuple.Item1.TES5Type == TES5BasicType.T_BOOL && valueTuple.Item2.TES5Type == TES5BasicType.T_INT) { int item2Value = ((TES5Integer)valueTuple.Item2).IntValue; if (item2Value != 0 && item2Value != 1) { throw new ConversionException("Unexpected Value: " + item2Value.ToString()); } ITES5Value newItem2 = new TES5Bool(item2Value == 1); newOp = op == TES5ComparisonExpressionOperator.OPERATOR_EQUAL ? op : TES5ComparisonExpressionOperator.OPERATOR_NOT_EQUAL; return(TES5ExpressionFactory.CreateComparisonExpression(valueTuple.Item1, newOp, newItem2)); } if (valueTuple.Item1.TES5Type == TES5BasicType.T_ACTOR && valueTuple.Item2.TES5Type == TES5BasicType.T_ACTORBASE) { return(TES5ExpressionFactory.CreateComparisonExpression(objectCallFactory.CreateGetActorBase((TES5ObjectCall)valueTuple.Item1), newOp, valueTuple.Item2)); } //WTM: Change: Added for se08barriertriggerscript if (newOp == TES5ComparisonExpressionOperator.OPERATOR_EQUAL && TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(valueTuple.Item1.TES5Type, TES5BasicType.T_FORM) && TES5InheritanceGraphAnalyzer.IsTypeOrExtendsType(valueTuple.Item2.TES5Type, TES5BasicType.T_FORM)) { TES5Reference reference1 = (TES5Reference)valueTuple.Item1; TES5Reference reference2 = (TES5Reference)valueTuple.Item2; reference1.ManualCastTo = TES5BasicType.T_FORM; reference2.ManualCastTo = TES5BasicType.T_FORM; return(TES5ExpressionFactory.CreateComparisonExpression(reference1, newOp, reference2)); } throw new ConversionException("Type could not be converted."); } TES5ComparisonExpression?containsCall = ConvertGetItemCountCallToContainsItemCall(valueTuple.Item1, op, valueTuple.Item2); //WTM: Change: Added if (containsCall != null) { return(containsCall); } flipOperator = true; } return(TES5ExpressionFactory.CreateComparisonExpression(leftValue, op, rightValue)); }