Ejemplo n.º 1
0
        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);
            }
        }
Ejemplo n.º 2
0
        public static ExportEntry InstallRandomSwitchIntoSequence(ExportEntry sequence, int numLinks)
        {
            var packageBin   = MERUtilities.GetEmbeddedStaticFilesBinaryFile("PremadeSeqObjs.pcc");
            var premadeObjsP = MEPackageHandler.OpenMEPackageFromStream(new MemoryStream(packageBin));

            // 1. Add the switch object and link it to the sequence
            var nSwitch = PackageTools.PortExportIntoPackage(sequence.FileRef, premadeObjsP.FindExport("SeqAct_RandomSwitch_0"), sequence.UIndex, false, true);

            KismetHelper.AddObjectToSequence(nSwitch, sequence);

            // 2. Generate the output links array. We will refresh the properties
            // with new structs so we don't have to make a copy constructor
            var olinks = nSwitch.GetProperty <ArrayProperty <StructProperty> >("OutputLinks");

            while (olinks.Count < numLinks)
            {
                olinks.Add(olinks[0]); // Just add a bunch of the first link
            }
            nSwitch.WriteProperty(olinks);

            // Reload the olinks with unique structs now
            olinks = nSwitch.GetProperty <ArrayProperty <StructProperty> >("OutputLinks");
            for (int i = 0; i < numLinks; i++)
            {
                olinks[i].GetProp <StrProperty>("LinkDesc").Value = $"Link {i + 1}";
            }

            nSwitch.WriteProperty(olinks);
            nSwitch.WriteProperty(new IntProperty(numLinks, "LinkCount"));
            return(nSwitch);
        }
Ejemplo n.º 3
0
        private static void MakeTubesSectionHarder()
        {
            var preReaperF = MERFileSystem.GetPackageFile("BioD_EndGm2_420CombatZone.pcc");

            if (preReaperF != null && File.Exists(preReaperF))
            {
                var preReaperP = MEPackageHandler.OpenMEPackage(preReaperF);

                // Open tubes on kills to start the attack (post platforms)----------------------
                var seq = preReaperP.GetUExport(15190);

                var attackSw = MERSeqTools.InstallRandomSwitchIntoSequence(seq, 2); //50% chance

                // killed squad member -> squad still exists to 50/50 sw
                KismetHelper.CreateOutputLink(preReaperP.GetUExport(15298), "SquadStillExists", attackSw);

                // 50/50 to just try to do reaper attack
                KismetHelper.CreateOutputLink(attackSw, "Link 1", preReaperP.GetUExport(14262));

                // Automate the platforms one after another
                KismetHelper.RemoveAllLinks(preReaperP.GetUExport(15010)); //B Plat01 Death
                KismetHelper.RemoveAllLinks(preReaperP.GetUExport(15011)); //B Plat02 Death

                // Sub automate - Remove attack completion gate inputs ----
                KismetHelper.RemoveAllLinks(preReaperP.GetUExport(15025)); //Plat03 Attack complete
                KismetHelper.RemoveAllLinks(preReaperP.GetUExport(15029)); //Plat02 Attack complete

                //// Sub automate - Remove activate input into gate
                var cmb2activated = preReaperP.GetUExport(15082);
                var cmb3activated = preReaperP.GetUExport(15087);

                KismetHelper.RemoveAllLinks(cmb2activated);
                KismetHelper.CreateOutputLink(cmb2activated, "Out", preReaperP.GetUExport(2657));

                // Delay the start of platform 3 by 4 seconds to give player a bit more time to handle first two platforms
                // Player will likely have decent weapons by now so they will be better than my testing for sure
                KismetHelper.RemoveAllLinks(cmb3activated);
                var newDelay = EntryCloner.CloneEntry(preReaperP.GetUExport(14307));
                newDelay.WriteProperty(new FloatProperty(4, "Duration"));
                KismetHelper.AddObjectToSequence(newDelay, preReaperP.GetUExport(15183), true);

                KismetHelper.CreateOutputLink(cmb3activated, "Out", newDelay);
                KismetHelper.CreateOutputLink(newDelay, "Finished", preReaperP.GetUExport(2659));
                //                preReaperP.GetUExport(14451).RemoveProperty("bOpen"); // Plat03 gate - forces gate open so when reaper attack fires it passes through
                //              preReaperP.GetUExport(14450).RemoveProperty("bOpen"); // Plat02 gate - forces gate open so when reaper attack fires it passes through


                // There is no end to Plat03 behavior until tubes are dead
                KismetHelper.CreateOutputLink(preReaperP.GetUExport(14469), "Completed", preReaperP.GetUExport(14374)); // Interp completed to Complete in Plat01
                KismetHelper.CreateOutputLink(preReaperP.GetUExport(14470), "Completed", preReaperP.GetUExport(14379)); // Interp completed to Complete in Plat02

                // if possession fails continue the possession loop on plat3 to end of pre-reaper combat
                KismetHelper.CreateOutputLink(preReaperP.GetUExport(16414), "Failed", preReaperP.GetUExport(14307));



                MERFileSystem.SavePackage(preReaperP);
            }
        }
Ejemplo n.º 4
0
        //me3 pcc to augment must be a map, and must have at least one BioTriggerStream and LevelStreamingKismet
        static void AugmentMapToLoadLiveEditor(IMEPackage pcc)
        {
            const string stateName = "SS_LIVEEDITOR";

            var mainSequence = pcc.Exports.First(exp => exp.ObjectName == "Main_Sequence" && exp.ClassName == "Sequence");
            var bioWorldInfo = pcc.Exports.First(exp => exp.ClassName == "BioWorldInfo");

            #region Sequencing

            var consoleEvent = SequenceObjectCreator.CreateSequenceObject(pcc, "SeqEvent_Console", MEGame.ME3);
            consoleEvent.WriteProperty(new NameProperty("LoadLiveEditor", "ConsoleEventName"));
            KismetHelper.AddObjectToSequence(consoleEvent, mainSequence);
            var setStreamingState = SequenceObjectCreator.CreateSequenceObject(pcc, "BioSeqAct_SetStreamingState", MEGame.ME3);
            setStreamingState.WriteProperty(new NameProperty(stateName, "StateName"));
            setStreamingState.WriteProperty(new BoolProperty(true, "NewValue"));
            KismetHelper.AddObjectToSequence(setStreamingState, mainSequence);
            KismetHelper.CreateOutputLink(consoleEvent, "Out", setStreamingState);

            var levelLoaded = SequenceObjectCreator.CreateSequenceObject(pcc, "SeqEvent_LevelLoaded", MEGame.ME3);
            KismetHelper.AddObjectToSequence(levelLoaded, mainSequence);
            var sendMessageToME3Exp = SequenceObjectCreator.CreateSequenceObject(pcc, "SeqAct_SendMessageToME3Explorer", MEGame.ME3);
            KismetHelper.AddObjectToSequence(sendMessageToME3Exp, mainSequence);
            KismetHelper.CreateOutputLink(levelLoaded, "Loaded and Visible", sendMessageToME3Exp);
            var stringVar = SequenceObjectCreator.CreateSequenceObject(pcc, "SeqVar_String", MEGame.ME3);
            stringVar.WriteProperty(new StrProperty(LoaderLoadedMessage, "StrValue"));
            KismetHelper.AddObjectToSequence(stringVar, mainSequence);
            KismetHelper.CreateVariableLink(sendMessageToME3Exp, "MessageName", stringVar);

            #endregion

            ExportEntry lsk = EntryCloner.CloneEntry(pcc.Exports.First(exp => exp.ClassName == "LevelStreamingKismet"));
            lsk.WriteProperty(new NameProperty(liveEditorFileName, "PackageName"));

            var streamingLevels = bioWorldInfo.GetProperty <ArrayProperty <ObjectProperty> >("StreamingLevels");
            streamingLevels.Add(new ObjectProperty(lsk));
            bioWorldInfo.WriteProperty(streamingLevels);

            ExportEntry bts             = EntryCloner.CloneTree(pcc.Exports.First(exp => exp.ClassName == "BioTriggerStream"));
            var         streamingStates = bts.GetProperty <ArrayProperty <StructProperty> >("StreamingStates");
            while (streamingStates.Count > 1)
            {
                streamingStates.RemoveAt(streamingStates.Count - 1);
            }
            streamingStates.Add(new StructProperty("BioStreamingState", new PropertyCollection
            {
                new NameProperty(stateName, "StateName"),
                new ArrayProperty <NameProperty>("VisibleChunkNames")
                {
                    new NameProperty(liveEditorFileName)
                }
            }));
            bts.WriteProperty(streamingStates);

            pcc.AddToLevelActorsIfNotThere(bts);
        }
Ejemplo n.º 5
0
        private static void InstallPlatformAutomation(ExportEntry seqActivated, ExportEntry delayToClone, ExportEntry finishSeq, int platIdx)
        {
            var seq = seqActivated.GetProperty <ObjectProperty>("ParentSequence").ResolveToEntry(seqActivated.FileRef) as ExportEntry;

            // Clone a delay object, set timer on it
            var delay = delayToClone.Clone();

            seqActivated.FileRef.AddExport(delay);
            KismetHelper.AddObjectToSequence(delay, seq, true);
            delay.WriteProperty(new FloatProperty(ThreadSafeRandom.NextFloat(3f, 10f - platIdx), "Duration"));

            // Point start to delay
            KismetHelper.CreateOutputLink(seqActivated, "Out", delay);

            // Point delay to finish
            KismetHelper.CreateOutputLink(delay, "Finished", finishSeq);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Clones basic data type objects. Do not use with complicated types.
        /// </summary>
        /// <param name="itemToClone"></param>
        /// <returns></returns>
        public static ExportEntry CloneBasicSequenceObject(ExportEntry itemToClone)
        {
            ExportEntry exp = itemToClone.Clone();

            //needs to have the same index to work properly
            if (exp.ClassName == "SeqVar_External")
            {
                // Probably shouldn't clone these...
                exp.indexValue = itemToClone.indexValue;
            }

            itemToClone.FileRef.AddExport(exp);

            var sequence = itemToClone.GetProperty <ObjectProperty>("ParentSequence").ResolveToEntry(itemToClone.FileRef) as ExportEntry;

            KismetHelper.AddObjectToSequence(exp, sequence);
            return(exp);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Removes a sequence element from the graph, by repointing incoming references to the ones referenced by outgoing items on this export. This is a very basic utility, only use it for items with one input and potentially multiple outputs.
        /// </summary>
        /// <param name="elementToSkip">Th sequence object to skip</param>
        /// <param name="outboundLinkIdx">The 0-indexed outbound link that should be attached the preceding entry element, as if this one had fired that link.</param>
        public static void SkipSequenceElement(ExportEntry elementToSkip, string outboundLinkName = null, int outboundLinkIdx = -1)
        {
            if (outboundLinkIdx == -1 && outboundLinkName == null)
            {
                throw new Exception(@"SkipSequenceElement() must have an outboundLinkName or an outboundLinkIdx!");
            }

            if (outboundLinkIdx == -1)
            {
                var outboundLinkNames = KismetHelper.GetOutboundLinkNames(elementToSkip);
                outboundLinkIdx = outboundLinkNames.IndexOf(outboundLinkName);
            }


            // List of outbound link elements on the specified item we want to skip. These will be placed into the inbound item
            Debug.WriteLine($@"Attempting to skip {elementToSkip.UIndex} in {elementToSkip.FileRef.FilePath}");
            var outboundLinkLists    = SeqTools.GetOutboundLinksOfNode(elementToSkip);
            var inboundToSkippedNode = SeqTools.FindOutboundConnectionsToNode(elementToSkip, SeqTools.GetAllSequenceElements(elementToSkip).OfType <ExportEntry>());

            var newTargetNodes = outboundLinkLists[outboundLinkIdx];

            foreach (var preNode in inboundToSkippedNode)
            {
                // For every node that links to the one we want to skip...
                var preNodeLinks = GetOutboundLinksOfNode(preNode);

                foreach (var ol in preNodeLinks)
                {
                    var numRemoved = ol.RemoveAll(x => x.LinkedOp == elementToSkip);

                    if (numRemoved > 0)
                    {
                        // At least one was removed. Repoint it
                        ol.AddRange(newTargetNodes);
                    }
                }

                WriteOutboundLinksToNode(preNode, preNodeLinks);
            }
        }
Ejemplo n.º 8
0
        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);
            }
        }
Ejemplo n.º 9
0
        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);
             * }*/
        }
Ejemplo n.º 10
0
        private static void GenericRandomizeFlyerSpawns(IMEPackage package, int maxNumNewEnemies, EPortablePawnClassification minClassification = EPortablePawnClassification.Mook, EPortablePawnClassification maxClassification = EPortablePawnClassification.Boss)
        {
            var flyerPrepSequences = package.Exports.Where(x => x.ClassName == "Sequence" && x.GetProperty <StrProperty>("ObjName") is StrProperty objName && objName == "REF_SpawnPrep_Flyer").ToList();

            foreach (var flySeq in flyerPrepSequences)
            {
                var objectsInSeq = KismetHelper.GetSequenceObjects(flySeq).OfType <ExportEntry>().ToList();
                var preGate      = objectsInSeq.FirstOrDefault(x => x.ClassName == "SeqAct_Gate"); // should not be null
                var outbound     = SeqTools.GetOutboundLinksOfNode(preGate);
                var aifactoryObj = outbound[0][0].LinkedOp as ExportEntry;                         //First out on first link. Should point to AIFactory assuming these are all duplicated flyers

                var availablePawns = PawnPorting.PortablePawns.Where(x => x.Classification >= minClassification && x.Classification <= maxClassification).ToList();
                if (availablePawns.Any())
                {
                    // We can add new pawns to install
                    List <PortablePawn> newPawnsInThisSeq = new List <PortablePawn>();
                    int numEnemies = 1;            // 1 is the original amount.
                    List <ExportEntry> aiFactories = new List <ExportEntry>();
                    aiFactories.Add(aifactoryObj); // the original one
                    for (int i = 0; i < maxNumNewEnemies; i++)
                    {
                        var randPawn = availablePawns.RandomElement();
                        if (!newPawnsInThisSeq.Contains(randPawn))
                        {
                            numEnemies++;
                            PawnPorting.PortPawnIntoPackage(randPawn, package);
                            newPawnsInThisSeq.Add(randPawn);
                            // Clone the ai factory sequence object and add it to the sequence
                            var newAiFactorySeqObj = EntryCloner.CloneTree(aifactoryObj);
                            aiFactories.Add(newAiFactorySeqObj);
                            KismetHelper.AddObjectToSequence(newAiFactorySeqObj, flySeq, false);

                            // Update the backing factory object
                            var backingFactory = newAiFactorySeqObj.GetProperty <ObjectProperty>("Factory").ResolveToEntry(package) as ExportEntry;
                            backingFactory.WriteProperty(new ObjectProperty(package.FindExport(randPawn.ChallengeTypeFullPath), "ActorType"));
                            var collection = backingFactory.GetProperty <ArrayProperty <ObjectProperty> >("ActorResourceCollection");
                            collection.Clear();
                            foreach (var asset in randPawn.AssetPaths)
                            {
                                collection.Add(new ObjectProperty(package.FindExport(asset)));
                            }
                            backingFactory.WriteProperty(collection);
                        }
                    }

                    if (newPawnsInThisSeq.Any())
                    {
                        // install the switch
                        var randSw = MERSeqTools.InstallRandomSwitchIntoSequence(flySeq, numEnemies);
                        outbound[0][0].LinkedOp = randSw;
                        SeqTools.WriteOutboundLinksToNode(preGate, outbound);

                        // Hook up switch to ai factories
                        for (int i = 0; i < numEnemies; i++)
                        {
                            var linkDesc = $"Link {i + 1}";
                            KismetHelper.CreateOutputLink(randSw, linkDesc, aiFactories[i]); // switches are indexed at 1
                        }
                    }
                }
            }
        }
Ejemplo n.º 11
0
        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);
            }
        }
Ejemplo n.º 12
0
        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);
        }