private static void AutomatePlatforming400(RandomizationOption option) { var platformControllerF = MERFileSystem.GetPackageFile("BioD_EndGm2_420CombatZone.pcc"); if (platformControllerF != null) { var platformController = MEPackageHandler.OpenMEPackage(platformControllerF); var delayToClone = platformController.GetUExport(14314); // Remove completion state from squad kills as we won't be using that mechanism KismetHelper.RemoveOutputLinks(platformController.GetUExport(14488)); //A Platform 01 KismetHelper.RemoveOutputLinks(platformController.GetUExport(14496)); //A Platform 02 KismetHelper.RemoveOutputLinks(platformController.GetUExport(14504)); //A Platform 03 KismetHelper.RemoveOutputLinks(platformController.GetUExport(14513)); //A Platform 0405 (together) // there's final platform with the controls on it. we don't touch it // Install delays and hook them up to the complection states InstallPlatformAutomation(platformController.GetUExport(15057), delayToClone, platformController.GetUExport(14353), 1); //01 to 02 InstallPlatformAutomation(platformController.GetUExport(15063), delayToClone, platformController.GetUExport(14358), 2); //02 to 03 InstallPlatformAutomation(platformController.GetUExport(15067), delayToClone, platformController.GetUExport(14363), 3); //03 to 0405 InstallPlatformAutomation(platformController.GetUExport(15072), delayToClone, platformController.GetUExport(14368), 4); //0405 to 06 MERFileSystem.SavePackage(platformController); } }
private static void GateTubesAttack() { // This doesn't actually work like expected, it seems gate doesn't store input value // Adds a gate to the tubes attack to ensure it doesn't fire while the previous attack is running still. var tubesF = MERFileSystem.GetPackageFile("BioD_EndGm2_425ReaperTubes.pcc"); if (tubesF != null && File.Exists(tubesF)) { var tubesP = MEPackageHandler.OpenMEPackage(tubesF); // Clone a gate var gateToClone = tubesP.GetUExport(1316); var seq = tubesP.GetUExport(1496); var newGate = EntryCloner.CloneEntry(gateToClone); newGate.RemoveProperty("bOpen"); // Make it open by default. KismetHelper.AddObjectToSequence(newGate, seq, true); // Hook up the 'START REAPER ATTACK' to the gate, remove it's existing output. var sraEvent = tubesP.GetUExport(1455); KismetHelper.RemoveOutputLinks(sraEvent); KismetHelper.CreateOutputLink(sraEvent, "Out", newGate, 0); // 0 = in, which means fire or queue for fire // Hook up the ending of the attack to the gate for 'open' so the gate can be passed through. var delay = tubesP.GetUExport(1273); KismetHelper.CreateOutputLink(tubesP.GetUExport(103), "Out", delay); // Attack finished (CameraShake_Intimidate) to 2s delay KismetHelper.RemoveAllLinks(delay); KismetHelper.CreateOutputLink(delay, "Finished", newGate, 1); //2s Delay to open gate // Make the gate automatically close itself on pass through, and configure output of gate to next item. KismetHelper.CreateOutputLink(newGate, "Out", newGate, 2); // Hook from Out to Close KismetHelper.CreateOutputLink(newGate, "Out", tubesP.GetUExport(1340), 0); // Hook from Out to Log (bypass the delay, we are repurposing it) MERFileSystem.SavePackage(tubesP); } }
private static void RandomizeTheLongWalk(RandomizationOption option) { var prelongwalkfile = MERFileSystem.GetPackageFile("BioD_EndGm2_200Factory.pcc"); if (prelongwalkfile != null) { // Pre-long walk selection var package = MEPackageHandler.OpenMEPackage(prelongwalkfile); var bioticTeamSeq = package.GetUExport(8609); var activated = package.GetUExport(8484); KismetHelper.RemoveAllLinks(activated); // install new logic var randSwitch = MERSeqTools.InstallRandomSwitchIntoSequence(bioticTeamSeq, 13); // don't include theif or veteran as dlc might not be installed KismetHelper.CreateOutputLink(activated, "Out", randSwitch); // Outputs of random choice KismetHelper.CreateOutputLink(randSwitch, "Link 1", package.GetUExport(1420)); //thane KismetHelper.CreateOutputLink(randSwitch, "Link 2", package.GetUExport(1419)); //jack KismetHelper.CreateOutputLink(randSwitch, "Link 3", package.GetUExport(1403)); //garrus KismetHelper.CreateOutputLink(randSwitch, "Link 4", package.GetUExport(1399)); //legion KismetHelper.CreateOutputLink(randSwitch, "Link 5", package.GetUExport(1417)); //grunt KismetHelper.CreateOutputLink(randSwitch, "Link 6", package.GetUExport(1395)); //jacob KismetHelper.CreateOutputLink(randSwitch, "Link 7", package.GetUExport(1418)); //samara KismetHelper.CreateOutputLink(randSwitch, "Link 8", package.GetUExport(1415)); //mordin KismetHelper.CreateOutputLink(randSwitch, "Link 9", package.GetUExport(1405)); //tali KismetHelper.CreateOutputLink(randSwitch, "Link 10", package.GetUExport(1401)); //morinth KismetHelper.CreateOutputLink(randSwitch, "Link 11", package.GetUExport(1402)); //miranda // kasumi if (MERFileSystem.GetPackageFile("BioH_Thief_00.pcc") != null) { KismetHelper.CreateOutputLink(randSwitch, "Link 12", package.GetUExport(1396)); //kasumi } // zaeed if (MERFileSystem.GetPackageFile("BioH_Veteran_00.pcc") != null) { KismetHelper.CreateOutputLink(randSwitch, "Link 13", package.GetUExport(1416)); //zaeed } MERFileSystem.SavePackage(package); } var biodEndGm2F = MERFileSystem.GetPackageFile("BioD_EndGm2.pcc"); if (biodEndGm2F != null) { var package = MEPackageHandler.OpenMEPackage(biodEndGm2F); var ts = package.GetUExport(7); var ss = ts.GetProperty <ArrayProperty <StructProperty> >("StreamingStates"); // Make walk4 remain loaded while walk5 is active as enemeis may not yet be cleared out var conclusion = ss[8]; var visibleNames = conclusion.GetProp <ArrayProperty <NameProperty> >("VisibleChunkNames"); if (!visibleNames.Any(x => x.Value == "BioD_EndGm2_300Walk04")) { // This has pawns as part of the level so we must make sure it doesn't disappear or player will just see enemies disappear visibleNames.Add(new NameProperty("BioD_EndGm2_300Walk04")); } ts.WriteProperty(ss); MERFileSystem.SavePackage(package); } var longwalkfile = MERFileSystem.GetPackageFile("BioD_EndGm2_300LongWalk.pcc"); if (longwalkfile != null) { // automate TLW var package = MEPackageHandler.OpenMEPackage(longwalkfile); var seq = package.GetUExport(1629); var stopWalking = package.GetUExport(1569); // The auto walk delay on Stop Walking var delay = package.GetUExport(806).Clone(); package.AddExport(delay); delay.WriteProperty(new FloatProperty(ThreadSafeRandom.NextFloat(2, 7), "Duration")); // how long to wait until auto walk KismetHelper.AddObjectToSequence(delay, seq, true); KismetHelper.CreateOutputLink(delay, "Finished", package.GetUExport(156)); KismetHelper.CreateOutputLink(stopWalking, "Out", delay); // Do not allow targeting the escort package.GetUExport(1915).WriteProperty(new IntProperty(0, "bValue")); // stopped walking package.GetUExport(1909).WriteProperty(new IntProperty(0, "bValue")); // loading from save - we will auto start KismetHelper.CreateOutputLink(package.GetUExport(1232), "Out", delay); // post loaded from save init // Do not enable autosaves, cause it makes it easy to cheese this area. Bypass the 'savegame' item KismetHelper.RemoveOutputLinks(package.GetUExport(156)); KismetHelper.CreateOutputLink(package.GetUExport(156), "Out", package.GetUExport(1106)); // Pick a random henchman to go on a date with //var determineEscortLog = package.GetUExport(1118); //var spawnSeq = package.GetUExport(1598); //// disconnect old logic //KismetHelper.RemoveAllLinks(determineEscortLog); // install new logic /*var randSwitch = SeqTools.InstallRandomSwitchIntoSequence(spawnSeq, 12); // don't include theif or veteran as dlc might not be installed * KismetHelper.CreateOutputLink(determineEscortLog, "Out", randSwitch); * * * // Outputs of random choice * * * * KismetHelper.CreateOutputLink(randSwitch, "Link 1", package.GetUExport(1599)); //thane * KismetHelper.CreateOutputLink(randSwitch, "Link 2", package.GetUExport(1601)); //jack * KismetHelper.CreateOutputLink(randSwitch, "Link 3", package.GetUExport(1603)); //garrus * KismetHelper.CreateOutputLink(randSwitch, "Link 4", package.GetUExport(1605)); //legion * KismetHelper.CreateOutputLink(randSwitch, "Link 5", package.GetUExport(1607)); //grunt * KismetHelper.CreateOutputLink(randSwitch, "Link 6", package.GetUExport(1609)); //jacob * KismetHelper.CreateOutputLink(randSwitch, "Link 7", package.GetUExport(1611)); //samara * KismetHelper.CreateOutputLink(randSwitch, "Link 8", package.GetUExport(1613)); //mordin * KismetHelper.CreateOutputLink(randSwitch, "Link 9", package.GetUExport(1615)); //tali * KismetHelper.CreateOutputLink(randSwitch, "Link 10", package.GetUExport(1619)); //morinth * KismetHelper.CreateOutputLink(randSwitch, "Link 11", package.GetUExport(1624)); //miranda */ MERFileSystem.SavePackage(package); } //randomize long walk lengths. var endwalkexportmap = new Dictionary <string, int>() { { "BioD_EndGm2_300Walk01", 40 }, { "BioD_EndGm2_300Walk02", 5344 }, { "BioD_EndGm2_300Walk03", 8884 }, { "BioD_EndGm2_300Walk04", 6370 }, { "BioD_EndGm2_300Walk05", 3190 } }; foreach (var map in endwalkexportmap) { var file = MERFileSystem.GetPackageFile(map.Key + ".pcc"); if (file != null) { var package = MEPackageHandler.OpenMEPackage(file); var export = package.GetUExport(map.Value); export.WriteProperty(new FloatProperty(ThreadSafeRandom.NextFloat(.5, 2.5), "PlayRate")); MERFileSystem.SavePackage(package); } } /*foreach (var f in files) * { * var package = MEPackageHandler.OpenMEPackage(f); * var animExports = package.Exports.Where(x => x.ClassName == "InterpTrackAnimControl"); * foreach (var anim in animExports) * { * var animseqs = anim.GetProperty<ArrayProperty<StructProperty>>("AnimSeqs"); * if (animseqs != null) * { * foreach (var animseq in animseqs) * { * var seqname = animseq.GetProp<NameProperty>("AnimSeqName").Value.Name; * if (seqname.StartsWith("Walk_")) * { * var playrate = animseq.GetProp<FloatProperty>("AnimPlayRate"); * var oldrate = playrate.Value; * if (oldrate != 1) Debugger.Break(); * playrate.Value = ThreadSafeRandom.NextFloat(.2, 6); * var data = anim.Parent.Parent as ExportEntry; * var len = data.GetProperty<FloatProperty>("InterpLength"); * len.Value = len.Value * playrate; //this might need to be changed if its not 1 * data.WriteProperty(len); * } * } * } * anim.WriteProperty(animseqs); * } * SavePackage(package); * }*/ }
private static void RandomizeAfterlifeShepDance() { var denDanceF = MERFileSystem.GetPackageFile(@"BioD_OmgHub_230DenDance.pcc"); if (denDanceF != null) { var loungeP = MEPackageHandler.OpenMEPackage(denDanceF); var sequence = loungeP.GetUExport(3924); MERPackageCache cache = new MERPackageCache(); List <InterpTools.InterpData> interpDatas = new List <InterpTools.InterpData>(); var interp1 = loungeP.GetUExport(3813); // Make 2 additional dance options by cloning the interp and the data tree var interp2 = MERSeqTools.CloneBasicSequenceObject(interp1); var interp3 = MERSeqTools.CloneBasicSequenceObject(interp1); // Clone the interp data for attaching to 2 and 3 var interpData1 = loungeP.GetUExport(1174); var interpData2 = EntryCloner.CloneTree(interpData1); var interpData3 = EntryCloner.CloneTree(interpData2); KismetHelper.AddObjectToSequence(interpData2, sequence); KismetHelper.AddObjectToSequence(interpData3, sequence); // Load ID for randomization interpDatas.Add(new InterpTools.InterpData(interpData1)); interpDatas.Add(new InterpTools.InterpData(interpData2)); interpDatas.Add(new InterpTools.InterpData(interpData3)); // Chance the data for interp2/3 var id2 = SeqTools.GetVariableLinksOfNode(interp2); id2[0].LinkedNodes[0] = interpData2; SeqTools.WriteVariableLinksToNode(interp2, id2); var id3 = SeqTools.GetVariableLinksOfNode(interp3); id3[0].LinkedNodes[0] = interpData3; SeqTools.WriteVariableLinksToNode(interp3, id3); // Add additional finished states for fadetoblack when done KismetHelper.CreateOutputLink(loungeP.GetUExport(958), "Finished", interp2, 2); KismetHelper.CreateOutputLink(loungeP.GetUExport(958), "Finished", interp3, 2); // Link up the random choice it makes var randSw = MERSeqTools.InstallRandomSwitchIntoSequence(sequence, 3); KismetHelper.CreateOutputLink(randSw, "Link 1", interp1); KismetHelper.CreateOutputLink(randSw, "Link 2", interp2); KismetHelper.CreateOutputLink(randSw, "Link 3", interp3); // Break the original output to start the interp, repoint it's output to the switch instead var sgm = loungeP.GetUExport(1003); //set gesture mode KismetHelper.RemoveOutputLinks(sgm); KismetHelper.CreateOutputLink(sgm, "Done", loungeP.GetUExport(960)); KismetHelper.CreateOutputLink(sgm, "Done", randSw); // Now install the dances foreach (var id in interpDatas) { var danceTrack = id.InterpGroups[0].Tracks[0]; OmegaHub.InstallShepardDanceGesture(danceTrack.Export, cache); } MERFileSystem.SavePackage(loungeP); } }
public static void RunGame2EmailMerge(GameTarget target) { M3MergeDLC.RemoveMergeDLC(target); var loadedFiles = MELoadedFiles.GetFilesLoadedInGame(target.Game, gameRootOverride: target.TargetPath); // File to base modifications on using IMEPackage pcc = MEPackageHandler.OpenMEPackage(loadedFiles[@"BioD_Nor103_Messages.pcc"]); // Path to Message templates file - different files for ME2/LE2 string ResourcesFilePath = $@"MassEffectModManagerCore.modmanager.emailmerge.{target.Game}.103Message_Template_{target.Game}"; using IMEPackage resources = MEPackageHandler.OpenMEPackageFromStream(Utilities.GetResourceStream(ResourcesFilePath)); // Startup file to place conditionals and transitions into using IMEPackage startup = MEPackageHandler.OpenMEPackageFromStream(Utilities.GetResourceStream( $@"MassEffectModManagerCore.modmanager.mergedlc.{target.Game}.Startup_{M3MergeDLC.MERGE_DLC_FOLDERNAME}.pcc")); var emailInfos = new List <ME2EmailMergeFile>(); var jsonSupercedances = M3Directories.GetFileSupercedances(target, new[] { @".json" }); if (jsonSupercedances.TryGetValue(EMAIL_MERGE_MANIFEST_FILE, out var jsonList)) { jsonList.Reverse(); foreach (var dlc in jsonList) { var jsonFile = Path.Combine(M3Directories.GetDLCPath(target), dlc, target.Game.CookedDirName(), EMAIL_MERGE_MANIFEST_FILE); emailInfos.Add(JsonConvert.DeserializeObject <ME2EmailMergeFile>(File.ReadAllText(jsonFile))); } } // Sanity checks if (!emailInfos.Any() || !emailInfos.SelectMany(e => e.Emails).Any()) { return; } if (emailInfos.Any(e => e.Game != target.Game)) { throw new Exception("ME2 email merge manifest targets incorrect game"); } // Startup File // Could replace this with full instanced path in M3 implementation ExportEntry stateEventMapExport = startup.Exports .First(e => e.ClassName == "BioStateEventMap" && e.ObjectName == "StateTransitionMap"); BioStateEventMap StateEventMap = stateEventMapExport.GetBinaryData <BioStateEventMap>(); ExportEntry ConditionalClass = startup.FindExport($@"PlotManager{M3MergeDLC.MERGE_DLC_FOLDERNAME}.BioAutoConditionals"); #region Sequence Exports // Send message - All email conditionals are checked and emails transitions are triggered ExportEntry SendMessageContainer = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Send_Messages"); ExportEntry LastSendMessage = KismetHelper.GetSequenceObjects(SendMessageContainer).OfType <ExportEntry>() .FirstOrDefault(e => { var outbound = KismetHelper.GetOutboundLinksOfNode(e); return(outbound.Count == 1 && outbound[0].Count == 0); }); ExportEntry TemplateSendMessage = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Send_MessageTemplate"); ExportEntry TemplateSendMessageBoolCheck = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Send_MessageTemplate_BoolCheck"); // Mark Read - email ints are set to read // This is the only section that does not gracefully handle different DLC installations - DLC_CER is required atm ExportEntry MarkReadContainer = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_Read"); ExportEntry LastMarkRead = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_Read.DLC_CER"); ExportEntry MarkReadOutLink = KismetHelper.GetOutboundLinksOfNode(LastMarkRead)[0][0].LinkedOp as ExportEntry; KismetHelper.RemoveOutputLinks(LastMarkRead); ExportEntry TemplateMarkRead = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_ReadTemplate"); ExportEntry TemplateMarkReadTransition = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_Read_Transition"); // Display Messages - Str refs are passed through to GUI ExportEntry DisplayMessageContainer = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Display_Messages"); ExportEntry DisplayMessageOutLink = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Display_Messages.SeqCond_CompareBool_0"); ExportEntry LastDisplayMessage = SeqTools.FindOutboundConnectionsToNode(DisplayMessageOutLink, KismetHelper.GetSequenceObjects(DisplayMessageContainer).OfType <ExportEntry>())[0]; KismetHelper.RemoveOutputLinks(LastDisplayMessage); var DisplayMessageVariableLinks = LastDisplayMessage.GetProperty <ArrayProperty <StructProperty> >("VariableLinks"); ExportEntry TemplateDisplayMessage = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Display_MessageTemplate"); // Archive Messages - Message ints are set to 3 ExportEntry ArchiveContainer = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Archive_Message"); ExportEntry ArchiveSwitch = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Archive_Message.SeqAct_Switch_0"); ExportEntry ArchiveOutLink = pcc.FindExport( @"TheWorld.PersistentLevel.Main_Sequence.Archive_Message.BioSeqAct_PMCheckConditional_1"); ExportEntry ExampleSetInt = KismetHelper.GetOutboundLinksOfNode(ArchiveSwitch)[0][0].LinkedOp as ExportEntry; ExportEntry ExamplePlotInt = SeqTools.GetVariableLinksOfNode(ExampleSetInt)[0].LinkedNodes[0] as ExportEntry; #endregion int messageID = KismetHelper.GetOutboundLinksOfNode(ArchiveSwitch).Count + 1; int currentSwCount = ArchiveSwitch.GetProperty <IntProperty>("LinkCount").Value; foreach (var emailMod in emailInfos) { string modName = "DLC_MOD_" + emailMod.ModName; foreach (var email in emailMod.Emails) { string emailName = modName + "_" + email.EmailName; // Create send transition int transitionId = WriteTransition(StateEventMap, email.StatusPlotInt); int conditionalId = WriteConditional(email.TriggerConditional); #region SendMessage ////////////// // SendMessage ////////////// // Create seq object var SMTemp = emailMod.InMemoryBool.HasValue ? TemplateSendMessageBoolCheck : TemplateSendMessage; EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, SMTemp, pcc, SendMessageContainer, true, new RelinkerOptionsPackage(), out var outSendEntry); var newSend = outSendEntry as ExportEntry; // Set name, comment, add to sequence newSend.ObjectName = new NameReference(emailName); KismetHelper.AddObjectToSequence(newSend, SendMessageContainer); KismetHelper.SetComment(newSend, emailName); if (target.Game == MEGame.ME2) { newSend.WriteProperty(new StrProperty(emailName, "ObjName")); } // Set Trigger Conditional var pmCheckConditionalSM = newSend.GetChildren() .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMCheckConditional" && e is ExportEntry); if (pmCheckConditionalSM is ExportEntry conditional) { conditional.WriteProperty(new IntProperty(conditionalId, "m_nIndex")); KismetHelper.SetComment(conditional, "Time for " + email.EmailName + "?"); } // Set Send Transition var pmExecuteTransitionSM = newSend.GetChildren() .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMExecuteTransition" && e is ExportEntry); if (pmExecuteTransitionSM is ExportEntry transition) { transition.WriteProperty(new IntProperty(transitionId, "m_nIndex")); KismetHelper.SetComment(transition, "Send " + email.EmailName + " message."); } // Set Send Transition if (emailMod.InMemoryBool.HasValue) { var pmCheckStateSM = newSend.GetChildren() .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMCheckState" && e is ExportEntry); if (pmCheckStateSM is ExportEntry checkState) { checkState.WriteProperty(new IntProperty(emailMod.InMemoryBool.Value, "m_nIndex")); KismetHelper.SetComment(checkState, "Is " + emailMod.ModName + " installed?"); } } // Hook up output links KismetHelper.CreateOutputLink(LastSendMessage, "Out", newSend); LastSendMessage = newSend; #endregion #region MarkRead /////////// // MarkRead /////////// // Create seq object var MRTemp = email.ReadTransition.HasValue ? TemplateMarkReadTransition : TemplateMarkRead; EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, MRTemp, pcc, MarkReadContainer, true, new RelinkerOptionsPackage(), out var outMarkReadEntry); var newMarkRead = outMarkReadEntry as ExportEntry; // Set name, comment, add to sequence newMarkRead.ObjectName = new NameReference(emailName); KismetHelper.AddObjectToSequence(newMarkRead, MarkReadContainer); KismetHelper.SetComment(newMarkRead, emailName); if (target.Game == MEGame.ME2) { newMarkRead.WriteProperty(new StrProperty(emailName, "ObjName")); } // Set Plot Int var storyManagerIntMR = newMarkRead.GetChildren() .FirstOrDefault(e => e.ClassName == "BioSeqVar_StoryManagerInt" && e is ExportEntry); if (storyManagerIntMR is ExportEntry plotIntMR) { plotIntMR.WriteProperty(new IntProperty(email.StatusPlotInt, "m_nIndex")); KismetHelper.SetComment(plotIntMR, email.EmailName); } if (email.ReadTransition.HasValue) { var pmExecuteTransitionMR = newMarkRead.GetChildren() .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMExecuteTransition" && e is ExportEntry); if (pmExecuteTransitionMR is ExportEntry transitionMR) { transitionMR.WriteProperty(new IntProperty(email.ReadTransition.Value, "m_nIndex")); KismetHelper.SetComment(transitionMR, "Trigger " + email.EmailName + " read transition"); } } // Hook up output links KismetHelper.CreateOutputLink(LastMarkRead, "Out", newMarkRead); LastMarkRead = newMarkRead; #endregion #region DisplayEmail //////////////// // Display Email //////////////// // Create seq object EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, TemplateDisplayMessage, pcc, DisplayMessageContainer, true, new RelinkerOptionsPackage(), out var outDisplayMessage); var newDisplayMessage = outDisplayMessage as ExportEntry; // Set name, comment, variable links, add to sequence newDisplayMessage.ObjectName = new NameReference(emailName); KismetHelper.AddObjectToSequence(newDisplayMessage, DisplayMessageContainer); newDisplayMessage.WriteProperty(DisplayMessageVariableLinks); KismetHelper.SetComment(newDisplayMessage, emailName); if (target.Game == MEGame.ME2) { newDisplayMessage.WriteProperty(new StrProperty(emailName, "ObjName")); } var displayChildren = newDisplayMessage.GetChildren(); // Set Plot Int var storyManagerIntDE = displayChildren.FirstOrDefault(e => e.ClassName == "BioSeqVar_StoryManagerInt" && e is ExportEntry); if (storyManagerIntDE is ExportEntry plotIntDE) { plotIntDE.WriteProperty(new IntProperty(email.StatusPlotInt, "m_nIndex")); } // Set Email ID var emailIdDE = displayChildren.FirstOrDefault(e => e.ClassName == "SeqVar_Int" && e is ExportEntry); if (emailIdDE is ExportEntry EmailIDDE) { EmailIDDE.WriteProperty(new IntProperty(messageID, "IntValue")); } // Set Title StrRef var titleStrRef = displayChildren.FirstOrDefault(e => e.ClassName == "BioSeqVar_StrRef" && e is ExportEntry ee && ee.GetProperty <NameProperty>("VarName").Value == "Title StrRef"); if (titleStrRef is ExportEntry Title) { Title.WriteProperty(new StringRefProperty(email.TitleStrRef, "m_srValue")); } // Set Description StrRef var descStrRef = displayChildren.FirstOrDefault(e => e.ClassName == "BioSeqVar_StrRef" && e is ExportEntry ee && ee.GetProperty <NameProperty>("VarName").Value == "Desc StrRef"); if (descStrRef is ExportEntry Desc) { Desc.WriteProperty(new StringRefProperty(email.DescStrRef, "m_srValue")); } // Hook up output links KismetHelper.CreateOutputLink(LastDisplayMessage, "Out", newDisplayMessage); LastDisplayMessage = newDisplayMessage; #endregion #region ArchiveEmail //////////////// // Archive Email //////////////// var NewSetInt = EntryCloner.CloneEntry(ExampleSetInt); KismetHelper.AddObjectToSequence(NewSetInt, ArchiveContainer); KismetHelper.CreateOutputLink(NewSetInt, "Out", ArchiveOutLink); KismetHelper.CreateNewOutputLink(ArchiveSwitch, "Link " + (messageID - 1), NewSetInt); var NewPlotInt = EntryCloner.CloneEntry(ExamplePlotInt); KismetHelper.AddObjectToSequence(NewPlotInt, ArchiveContainer); NewPlotInt.WriteProperty(new IntProperty(email.StatusPlotInt, "m_nIndex")); NewPlotInt.WriteProperty(new StrProperty(emailName, "m_sRefName")); var linkedVars = SeqTools.GetVariableLinksOfNode(NewSetInt); linkedVars[0].LinkedNodes = new List <IEntry>() { NewPlotInt }; SeqTools.WriteVariableLinksToNode(NewSetInt, linkedVars); messageID++; currentSwCount++; #endregion } } KismetHelper.CreateOutputLink(LastMarkRead, "Out", MarkReadOutLink); KismetHelper.CreateOutputLink(LastDisplayMessage, "Out", DisplayMessageOutLink); ArchiveSwitch.WriteProperty(new IntProperty(currentSwCount, "LinkCount")); stateEventMapExport.WriteBinary(StateEventMap); // Save Messages file into DLC var cookedDir = Path.Combine(M3Directories.GetDLCPath(target), M3MergeDLC.MERGE_DLC_FOLDERNAME, target.Game.CookedDirName()); var outMessages = Path.Combine(cookedDir, @"BioD_Nor103_Messages.pcc"); pcc.Save(outMessages); // Save Startup file into DLC var startupF = Path.Combine(cookedDir, $@"Startup_{M3MergeDLC.MERGE_DLC_FOLDERNAME}.pcc"); startup.Save(startupF); }