private async void StartRandomization()
        {
            var modPath      = MERFileSystem.GetDLCModPath();
            var backupStatus = BackupService.GetBackupStatus(MERFileSystem.Game);

            if (!backupStatus.BackedUp && !Directory.Exists(modPath))
            {
                var settings = new MetroDialogSettings()
                {
                    AffirmativeButtonText = "Continue anyways",
                    NegativeButtonText    = "Cancel"
                };
                var result = await this.ShowMessageAsync("No ME3Tweaks-based backup availbale", "It is recommended that you create an ME3Tweaks-based backup before randomization, as this allows much faster re-rolls. You can take a backup using the button on the bottom left of the interface.", MessageDialogStyle.AffirmativeAndNegative, settings);

                if (result == MessageDialogResult.Negative)
                {
                    // Do nothing. User canceled
                    return;
                }
            }


            if (Directory.Exists(modPath) && PerformReroll)
            {
                var isControllerInstalled = SFXGame.IsControllerBasedInstall();
                if (!isControllerInstalled)
                {
                    if (backupStatus.BackedUp)
                    {
                        var settings = new MetroDialogSettings()
                        {
                            AffirmativeButtonText    = "Quick restore",
                            NegativeButtonText       = "No restore",
                            FirstAuxiliaryButtonText = "Cancel",
                            DefaultButtonFocus       = MessageDialogResult.Affirmative
                        };
                        var result = await this.ShowMessageAsync("Existing randomization already installed", "An existing randomization is already installed. It is highly recommended that you perform a quick restore before re-rolling so that basegame changes do not stack or are left installed if your new options do not include these changes.\n\nPerform a quick restore before randomization?", MessageDialogStyle.AffirmativeAndNegativeAndSingleAuxiliary, settings);

                        if (result == MessageDialogResult.FirstAuxiliary)
                        {
                            // Do nothing. User canceled
                            return;
                        }

                        if (result == MessageDialogResult.Affirmative)
                        {
                            // Perform quick restore first
                            RestoreController.StartRestore(this, true, InternalStartRandomization);
                            return; // Return, we will run randomization after this
                        }

                        // User did not want to restore, just run
                    }
                    else
                    {
                        var settings = new MetroDialogSettings()
                        {
                            AffirmativeButtonText = "Continue anyways",
                            NegativeButtonText    = "Cancel",
                        };
                        var result = await this.ShowMessageAsync("Existing randomization already installed", "An existing randomization is already installed. Some basegame only randomized files may remain after the DLC component is removed, and if options that modify these files are selected, the effects will stack. It is recommended you 'Remove Randomization' in the bottom left window, then repair your game to ensure you have a fresh installation for a re-roll.\n\nAn ME3Tweaks-based backup is recommended to avoid this procedure, which can be created in the bottom left of the application. It enables the quick restore feature, which only takes a few seconds.", MessageDialogStyle.AffirmativeAndNegative, settings);

                        if (result == MessageDialogResult.Negative)
                        {
                            // Do nothing. User canceled
                            return;
                        }
                    }
                }
                else
                {
                    if (backupStatus.BackedUp)
                    {
                        var settings = new MetroDialogSettings()
                        {
                            AffirmativeButtonText     = "Perform quick restore + randomize",
                            NegativeButtonText        = "Perform only quick restore",
                            FirstAuxiliaryButtonText  = "Install anyways",
                            SecondAuxiliaryButtonText = "Cancel",

                            DefaultButtonFocus = MessageDialogResult.Negative
                        };
                        var result = await this.ShowMessageAsync("Controller mod detected", "Performing a quick restore will undo changes made by the ME2Controller mod. After performing a quick restore, but before randomization, you should reinstall ME2Controller.", MessageDialogStyle.AffirmativeAndNegativeAndDoubleAuxiliary, settings);

                        if (result == MessageDialogResult.SecondAuxiliary)
                        {
                            // Do nothing. User canceled
                            return;
                        }

                        if (result == MessageDialogResult.Affirmative)
                        {
                            // Perform quick restore first
                            RestoreController.StartRestore(this, true, InternalStartRandomization);
                            return; // Return, we will run randomization after this
                        }

                        if (result == MessageDialogResult.Negative)
                        {
                            RestoreController.StartRestore(this, true);
                            return; // Return, we will run randomization after this
                        }
                        // User did not want to restore, just run
                    }
                    else
                    {
                        // no backup, can't quick restore
                        var settings = new MetroDialogSettings()
                        {
                            AffirmativeButtonText = "Continue anyways",
                            NegativeButtonText    = "Cancel",
                        };
                        var result = await this.ShowMessageAsync("Existing randomization already installed", "An existing randomization is already installed. Some basegame only randomized files may remain after the DLC component is removed, and if options that modify these files are selected, the effects will stack. It is recommended you 'Remove Randomization' in the bottom left window, then repair your game to ensure you have a fresh installation for a re-roll.\n\nAn ME3Tweaks-based backup is recommended to avoid this procedure, which can be created in the bottom left of the application. It enables the quick restore feature, which only takes a few seconds.", MessageDialogStyle.AffirmativeAndNegative, settings);

                        if (result == MessageDialogResult.Negative)
                        {
                            // Do nothing. User canceled
                            return;
                        }
                    }
                }
            }

            InternalStartRandomization();
        }
 public virtual bool IsAssetFileAvailable()
 {
     return(MERFileSystem.GetPackageFile(PackageFile, false) != null);
 }
        private static void RandomizeDancer()
        {
            var loungeF = MERFileSystem.GetPackageFile("BioD_TwrHub_202Lounge.pcc");

            if (loungeF != null && File.Exists(loungeF))
            {
                var package = MEPackageHandler.OpenMEPackage(loungeF);
                var bodySM  = package.GetUExport(4509);
                var headSM  = package.GetUExport(2778);

                // Install new head and body assets
                var newInfo = DancerOptions.RandomElement();
                while (newInfo.BodyAsset != null && !newInfo.BodyAsset.IsAssetFileAvailable())
                {
                    // Find another asset that is available
                    MERLog.Information($@"Asset {newInfo.BodyAsset.AssetPath} in {newInfo.BodyAsset.PackageFile} not available, repicking...");
                    newInfo = DancerOptions.RandomElement();
                }
                var newBody = PackageTools.PortExportIntoPackage(package, newInfo.BodyAsset.GetAsset());
                bodySM.WriteProperty(new ObjectProperty(newBody.UIndex, "SkeletalMesh"));

                if (newInfo.HeadAsset != null)
                {
                    var newHead = PackageTools.PortExportIntoPackage(package, newInfo.HeadAsset.GetAsset());
                    headSM.WriteProperty(new ObjectProperty(newHead.UIndex, "SkeletalMesh"));
                }
                else if (!newInfo.KeepHead)
                {
                    headSM.RemoveProperty("SkeletalMesh");
                }


                if (newInfo.DrawScale != 1)
                {
                    // Install DS3D on the archetype. It works. Not gonna question it
                    var ds = new CFVector3()
                    {
                        X = newInfo.DrawScale,
                        Y = newInfo.DrawScale,
                        Z = newInfo.DrawScale,
                    };
                    package.GetUExport(619).WriteProperty(ds.ToLocationStructProperty("DrawScale3D")); //hack
                }

                // Install any updates to locations/rotations
                var dancerInstance = package.GetUExport(4510); // contains location data for dancer which may need to be slightly adjusted
                if (newInfo.Location != null)
                {
                    dancerInstance.WriteProperty(newInfo.Location.ToLocationStructProperty("Location"));
                }
                if (newInfo.Rotation != null)
                {
                    dancerInstance.WriteProperty(newInfo.Rotation.ToRotatorStructProperty("Rotation"));
                }

                if (newInfo.MorphFace != null)
                {
                    var newHead = PackageTools.PortExportIntoPackage(package, newInfo.MorphFace.GetAsset());
                    headSM.WriteProperty(new ObjectProperty(newHead.UIndex, "MorphHead"));
                }
                MERFileSystem.SavePackage(package);
            }
        }
Esempio n. 4
0
        public static async void StartRestore(MainWindow mw, bool isQuick, Action postRestoreDelegate = null)
        {
            var pd = await mw.ShowProgressAsync("Restoring game", "Preparing to restore game");

            pd.SetIndeterminate();
            await Task.Run(() =>
            {
                if (isQuick)
                {
                    // Nuke the DLC
                    MERLog.Information(@"Quick restore started");
                    pd.SetMessage("Removing randomize DLC component");
                    var dlcModPath = MERFileSystem.GetDLCModPath();
                    if (Directory.Exists(dlcModPath))
                    {
                        MERLog.Information($@"Deleting {dlcModPath}");
                        Utilities.DeleteFilesAndFoldersRecursively(dlcModPath);
                    }

                    mw.DLCComponentInstalled = false;


                    // Restore basegame only files
                    pd.SetMessage("Restoring randomized basegame files");
                    var isControllerModInstalled = SFXGame.IsControllerBasedInstall();

                    var backupPath       = BackupService.GetGameBackupPath(MERFileSystem.Game, out _, false);
                    var gameCookedPath   = M3Directories.GetCookedPath(Locations.GetTarget(MERFileSystem.Game));
                    var backupCookedPath = MEDirectories.GetCookedPath(MERFileSystem.Game, backupPath);
                    foreach (var bgf in MERFileSystem.alwaysBasegameFiles)
                    {
                        var srcPath  = Path.Combine(backupCookedPath, bgf);
                        var destPath = Path.Combine(gameCookedPath, bgf);
                        MERLog.Information($@"Restoring {bgf}");
                        File.Copy(srcPath, destPath, true);
                    }

                    if (isControllerModInstalled)
                    {
                        // We must also restore Coalesced.ini or it will reference a UI that is no longer available and game will not boot
                        MERLog.Information(@"Controller based install detected, also restoring Coalesced.ini to prevent startup crash");
                        File.Copy(Path.Combine(backupPath, "BioGame", "Config", "PC", "Cooked", "Coalesced.ini"), Path.Combine(Locations.GetTarget(MERFileSystem.Game).TargetPath, "BioGame", "Config", "PC", "Cooked", "Coalesced.ini"), true);
                    }

                    // Delete basegame TFC
                    var baseTFC = MERFileSystem.GetTFCPath(false);
                    if (File.Exists(baseTFC))
                    {
                        File.Delete(baseTFC);
                    }

                    // Done!
                }
                else
                {
                    // Full restore
                    var target = Locations.GetTarget(MERFileSystem.Game);
                    MERLog.Information($@"Performing full game restore on {target.TargetPath} target after restore");

                    object syncObj = new object();
                    BackupHandler.GameRestore gr = new BackupHandler.GameRestore(MERFileSystem.Game)
                    {
                        ConfirmationCallback = (title, message) =>
                        {
                            bool response = false;
                            Application.Current.Dispatcher.Invoke(async() =>
                            {
                                response = await mw.ShowMessageAsync(title, message,
                                                                     MessageDialogStyle.AffirmativeAndNegative,
                                                                     new MetroDialogSettings()
                                {
                                    AffirmativeButtonText = "OK",
                                    NegativeButtonText    = "Cancel",
                                }) == MessageDialogResult.Affirmative;
                                lock (syncObj)
                                {
                                    Monitor.Pulse(syncObj);
                                }
                            });
                            lock (syncObj)
                            {
                                Monitor.Wait(syncObj);
                            }

                            return(response);
                        },
                        BlockingErrorCallback = (title, message) => { Application.Current.Dispatcher.Invoke(async() => { await mw.ShowMessageAsync(title, message); }); },
                        RestoreErrorCallback  = (title, message) => { Application.Current.Dispatcher.Invoke(async() => { await mw.ShowMessageAsync(title, message); }); },
                        UpdateStatusCallback  = message =>
                                                Application.Current.Dispatcher.Invoke(() => pd.SetMessage(message)),
                        UpdateProgressCallback = (done, total) =>
                                                 Application.Current.Dispatcher.Invoke(() =>
                        {
                            pd.SetProgress(done * 1d / total);
                            if (total != 0)
                            {
                                TaskbarHelper.SetProgressState(TaskbarProgressBarState.Normal);
                                TaskbarHelper.SetProgress(done * 1.0 / total);
                            }
                        }),
                        SetProgressIndeterminateCallback = indeterminate => Application.Current.Dispatcher.Invoke(() =>
                        {
                            if (indeterminate)
                            {
                                pd.SetIndeterminate();
                            }
                            TaskbarHelper.SetProgressState(indeterminate ? TaskbarProgressBarState.Indeterminate : TaskbarProgressBarState.Normal);
                        }),
                        SelectDestinationDirectoryCallback = (title, message) =>
                        {
                            string selectedPath = null;
                            Application.Current.Dispatcher.Invoke(() =>
                            {
                                // Not sure if this has to be synced
                                CommonOpenFileDialog ofd = new CommonOpenFileDialog()
                                {
                                    Title            = "Select restore destination directory",
                                    IsFolderPicker   = true,
                                    EnsurePathExists = true
                                };
                                if (ofd.ShowDialog() == CommonFileDialogResult.Ok)
                                {
                                    selectedPath = ofd.FileName;
                                }
                            });
                            return(selectedPath);
                        }
                    };
                    gr.PerformRestore(target.TargetPath);
                    mw.DLCComponentInstalled = false;
                    MERLog.Information(@"Reloading target after restore");
                    target.ReloadGameTarget(false, false);
                    mw.SetupTargetDescriptionText();
                }
            }).ContinueWithOnUIThread(async x =>
            {
                TaskbarHelper.SetProgressState(TaskbarProgressBarState.NoProgress);
                await pd.CloseAsync();
                postRestoreDelegate?.Invoke();
            });
        }
Esempio n. 5
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);
            }
        }
        public static bool RandomizePackageActorsInConversation(IMEPackage package, RandomizationOption option)
        {
            var conversationStartExports = package.Exports.Where(CanRandomizeSeqActStartConvo).ToList();

            if (!conversationStartExports.Any())
            {
                return(false);
            }

            MERPackageCache localCache = new MERPackageCache();

            foreach (var convStart in conversationStartExports)
            {
                //if (convStart.UIndex < 13638)
                //    continue;
                if (!CanRandomizeConversationStart(convStart))
                {
                    continue;
                }
                var bioConvImportProp = convStart.GetProperty <ObjectProperty>("Conv");
                if (bioConvImportProp == null)
                {
                    continue; // Some conversation starts are just filler stubs and are missing data like Nor_340a/bZaeed
                }
                var           bioConvImport = bioConvImportProp.ResolveToEntry(package) as ImportEntry;
                List <string> inputTags     = new();

                // Shuffle the inputs to the conversation. We will store these and then have to update the Owner and Player tags
                // I think......
                var seqLinks = SeqTools.GetVariableLinksOfNode(convStart);

                // Dictionary of linked nodes, and var links that point to them.
                List <ExportEntry>          shufflableNodes = new List <ExportEntry>();
                List <SeqTools.VarLinkInfo> applicableLinks = new();
                ExportEntry ownerEntry      = null;
                ExportEntry playerEntry     = null;
                var         sequenceObjects = SeqTools.GetAllSequenceElements(convStart).OfType <ExportEntry>().ToList();
                foreach (var varilink in seqLinks)
                {
                    if (CanLinkBeRandomized(varilink, out _))
                    {
                        var connectedItem = varilink.LinkedNodes[0] as ExportEntry;
                        if (!shufflableNodes.Contains(connectedItem))
                        {
                            // Check to make sure node has a value
                            if (connectedItem.ClassName == "SeqVar_Object")
                            {
                                var objValue = connectedItem.GetProperty <ObjectProperty>("ObjValue");
                                if (objValue == null && !MERSeqTools.IsAssignedBioPawn(convStart, connectedItem, sequenceObjects))
                                {
                                    continue; // This is not a shufflable node, it is never assigned anything
                                }
                            }

                            shufflableNodes.Add(connectedItem);
                        }

                        if (varilink.LinkedNodes[0].ClassName == "SeqVar_Player")
                        {
                            playerEntry = varilink.LinkedNodes[0] as ExportEntry;
                        }
                        else if (varilink.LinkDesc == "Owner")
                        {
                            ownerEntry = varilink.LinkedNodes[0] as ExportEntry;
                        }

                        applicableLinks.Add(varilink);
                    }
                }

                if (shufflableNodes.Count <= 1)
                {
                    continue; // We cannot edit this one
                }
                if (shufflableNodes.Count == 2 && playerEntry != null && ownerEntry != null)
                {
                    continue; // We can't swap owner and player due to hardcoded owner and player tags
                }
                // Build shuffle map
                bool retry = true;
                Dictionary <int, int> shuffleMap = null;
                while (retry)
                {
                    shuffleMap = new Dictionary <int, int>();
                    var reAssigned = shufflableNodes.ToList();
                    reAssigned.Shuffle();

                    for (int i = 0; i < shufflableNodes.Count; i++)
                    {
                        var sourceEntry = shufflableNodes[i];
                        var remapEntry  = reAssigned.PullFirstItem();

                        int retryCount = reAssigned.Count;
                        while (retryCount > 0 && (sourceEntry == remapEntry || (ownerEntry == sourceEntry && remapEntry == ownerEntry)))
                        {
                            reAssigned.Add(remapEntry);
                            sourceEntry = reAssigned.PullFirstItem();
                            retryCount--;
                        }

                        if (sourceEntry == ownerEntry && remapEntry == playerEntry)
                        {
                            // Cannot set player to owner
                            break; // We must force a retry
                        }

                        shuffleMap[sourceEntry.UIndex] = remapEntry.UIndex;
                    }

                    if (shuffleMap.Count != shufflableNodes.Count)
                    {
                        continue; // Try again
                    }
                    // We did it
                    retry = false;
                }

                // Apply the shuffle map
                Dictionary <NameReference, ActorLookup> findActorMap = new();

                foreach (var varilink in applicableLinks)
                {
                    var repointedItem = shuffleMap[varilink.LinkedNodes[0].UIndex];
                    //if (varilink.LinkedNodes[0] == playerEntry || repointedItem == playerEntry.UIndex)
                    //{
                    // Build FindActor mapping for player
                    // it should be:
                    // Player -> [Some actor, like Pup1_1]
                    // Pup1_1 -> Player
                    // When parsing the interpdatas, change the findactor's
                    // by this methodology
                    BuildActorMap(findActorMap, varilink, repointedItem);
                    //}

                    // Actor map for updating the bioconversation

                    //Debug.WriteLine($"Shuffle actor on varilink in convo: {varilink.LinkedNodes[0].ObjectName.Instanced} => {package.GetUExport(repointedItem).ObjectName.Instanced}");
                    varilink.LinkedNodes[0] = package.GetUExport(repointedItem);
                }

                //SeqTools.PrintVarLinkInfo(seqLinks);

                // Write the updated links out.
                SeqTools.WriteVariableLinksToNode(convStart, seqLinks);



                // Update the localizations
                foreach (var loc in Localizations)
                {
                    var bioConversation = EntryImporter.ResolveImport(bioConvImport, MERFileSystem.GetGlobalCache(), localCache, loc);
                    var conv            = new ConversationExtended(bioConversation);
                    conv.LoadConversation(null, true);

                    // Step 1. Update tags via map
                    var allConvEntries = conv.ReplyList.ToList();
                    allConvEntries.AddRange(conv.EntryList);
                    foreach (var convNode in allConvEntries)
                    {
                        // Update speaker
                        if (convNode.IsReply)
                        {
                            // Player. We can't do anything (or can we?)
                        }
                        else
                        {
                            // Non-player node. We can change the tag
                            var speakerTag = convNode.SpeakerTag;

                            // Even though it is dictionary, since it is NameRef, it is considered case sensitive. We have to use case insensitive check
                            var newName = findActorMap.FirstOrDefault(x => x.Key.Instanced.Equals(speakerTag.SpeakerName, StringComparison.InvariantCultureIgnoreCase)).Value;
                            if (newName != null && newName.FindActor.Name != null)
                            {
                                var newTagIdx = conv.Speakers.FirstOrDefault(x => x.SpeakerName.Equals(newName.FindActor.Instanced, StringComparison.InvariantCultureIgnoreCase));
                                if (newTagIdx != null)
                                {
                                    convNode.SpeakerIndex = newTagIdx.SpeakerID;
                                }
                                else
                                {
                                    var newSpeaker = new SpeakerExtended(conv.Speakers.Count - 3, new NameReference(newName.FindActor.Name.ToLower(), newName.FindActor.Number));
                                    newSpeaker.FaceFX_Male   = speakerTag.FaceFX_Male;
                                    newSpeaker.FaceFX_Female = speakerTag.FaceFX_Male;

                                    conv.Speakers.Add(newSpeaker);
                                    convNode.SpeakerIndex = newSpeaker.SpeakerID;
                                    //Debugger.Break();
                                }
                            }
                            else
                            {
                                //Debugger.Break();
                            }
                        }



                        // Update interpolation data
                        if (convNode.Interpdata == null)
                        {
                            continue;
                        }
                        var interpData = convNode.Interpdata;

                        InterpData id    = new InterpData(interpData);
                        var        convo = id.InterpGroups.FirstOrDefault(x => x.GroupName == "Conversation");
                        if (convo != null)
                        {
                            foreach (var it in convo.Tracks)
                            {
                                var props     = it.Export.GetProperties();
                                var findActor = props.GetProp <NameProperty>("m_nmFindActor");
                                if (findActor != null && findActor.Value.Name != "Owner" && findActorMap.TryGetValue(findActor.Value, out var newInfo) && newInfo.FindActor.Name != null)
                                {
                                    //Debug.WriteLine($"Updating find actor info: {findActor.Value.Instanced} -> {newInfo.FindActor.Instanced}");
                                    findActor.Value = newInfo.FindActor;
                                    if (newInfo.FindMode != null)
                                    {
                                        props.AddOrReplaceProp(new EnumProperty(newInfo.FindMode.ToString(), "EActorTrackFindActorMode", MERFileSystem.Game, "m_eFindActorMode"));
                                    }
                                    else
                                    {
                                        props.RemoveNamedProperty("m_eFindActorMode");
                                    }
                                }

                                var lookAtKeys = props.GetProp <ArrayProperty <StructProperty> >("m_aLookAtKeys");
                                if (lookAtKeys != null)
                                {
                                    foreach (var lookAtS in lookAtKeys)
                                    {
                                        var lookAt = lookAtS.GetProp <NameProperty>("nmFindActor");

                                        if (lookAt.Value.Name != "Owner" && findActorMap.TryGetValue(lookAt.Value, out var newInfoLA) && newInfoLA.FindActor.Name != null)
                                        {
                                            //Debug.WriteLine($"Updating lookat find actor info: {lookAt.Value.Instanced} -> {newInfoLA.FindActor.Instanced}");
                                            if (newInfoLA.FindActor.Name == null)
                                            {
                                                Debugger.Break();
                                            }
                                            lookAt.Value = newInfoLA.FindActor;
                                            var lookatFindMode = newInfoLA.FindMode?.ToString();
                                            lookatFindMode ??= "ActorTrack_FindActorByTag"; // if it's null, set it to the default. As this is struct, the property must exist
                                            lookAtS.Properties.AddOrReplaceProp(new EnumProperty(lookatFindMode, "EActorTrackFindActorMode", MERFileSystem.Game, "eFindActorMode"));
                                        }
                                    }
                                }

                                it.Export.WriteProperties(props);

                                //if (IsAllowedFindActor(findActor))
                                //{
                                //    if (actorsToFind.All(x => x.FindActor.Instanced != findActor.Value.Instanced))
                                //    {

                                //        ActorLookup al = new ActorLookup() { FindActor = findActor.Value };
                                //        var lookupType = it.Export.GetProperty<EnumProperty>("m_eFindActorMode");
                                //        if (lookupType != null && Enum.TryParse<EActorTrackFindActorMode>(lookupType.Value.Name, out var result))
                                //        {
                                //            al.FindMode = result;
                                //        }

                                //        actorsToFind.Add(al);
                                //    }

                                //    // add track
                                //    tracksToUpdate.Add(it);
                                //}
                            }
                        }
                    }
                    conv.SerializeNodes(); // Write the updated info back
                    MERFileSystem.SavePackage(bioConversation.FileRef);
                }
            }

            //// Step 2. Build the remapping
            //if (actorsToFind.Count <= 1)
            //    return false; // Nothing to randomize

            //// Instanced name to NameReference
            //Dictionary<string, ActorLookup> actorRemap = new Dictionary<string, ActorLookup>();
            //var shuffledActors = actorsToFind.ToList();
            //var unshuffledActors = actorsToFind.Select(x => x.FindActor.Instanced).ToList();
            //shuffledActors.Shuffle();

            //Debug.WriteLine("");
            //while (shuffledActors.Count > 0)
            //{
            //    var sourceItem = unshuffledActors.PullFirstItem();
            //    var remappedItem = shuffledActors.PullFirstItem();
            //    actorRemap[sourceItem] = remappedItem;
            //    Debug.WriteLine($"Remapping actor: {sourceItem} => {remappedItem.FindActor.Instanced}");
            //}

            //// Step 3. Update all tracks with new remap
            //foreach (var track in tracksToUpdate)
            //{
            //    var props = track.Export.GetProperties();
            //    var findActor = props.GetProp<NameProperty>("m_nmFindActor");
            //    if (IsAllowedFindActor(findActor))
            //    {
            //        if (actorRemap[findActor.Value.Instanced].FindMode != null)
            //        {
            //            props.AddOrReplaceProp(new EnumProperty(actorRemap[findActor.Value.Instanced].FindMode.ToString(), "EActorTrackFindActorMode", MERFileSystem.Game, "m_eFindActorMode"));
            //        }
            //        else
            //        {
            //            props.RemoveNamedProperty("m_eFindActorNode");
            //        }
            //        findActor.Value = actorRemap[findActor.Value.Instanced].FindActor;
            //        track.Export.WriteProperties(props);
            //    }
            //}


            return(true);
        }
Esempio n. 7
0
        public static bool InstallOHKO(RandomizationOption arg)
        {
            MERLog.Information("Installing One-Hit KO");

            var sfxgame = MERFileSystem.GetPackageFile("SFXGame.pcc");

            if (sfxgame != null && File.Exists(sfxgame))
            {
                var sfxgameP = MEPackageHandler.OpenMEPackage(sfxgame);

                // Blood on screen VFX
                sfxgameP.GetUExport(29336).RemoveProperty("BleedOutEventPair");
                sfxgameP.GetUExport(29336).RemoveProperty("BleedOutVFXTemplate");

                // Prevent weird landing glitch
                var fallingStateLanded = sfxgameP.GetUExport(11293);
                var landedData         = fallingStateLanded.Data;
                NopRange(landedData, 0x2C, 0x14);
                fallingStateLanded.Data = landedData;

                MERFileSystem.SavePackage(sfxgameP);
            }
            else
            {
            }


            // ProCer tutorials setting min1Health
            SetupProCer();

            // Player classes - Remove shields, set maxhealth to 1
            string[] classes = new[] { "Adept", "Engineer", "Infiltrator", "Sentinel", "Soldier", "Vanguard" };
            foreach (var c in classes)
            {
                var charClass = MERFileSystem.GetPackageFile($"SFXCharacterClass_{c}.pcc");
                if (charClass != null && File.Exists(charClass))
                {
                    var charClassP = MEPackageHandler.OpenMEPackage(charClass);
                    var ccLoadout  = charClassP.FindExport($"BioChar_Loadouts.Player.PLY_{c}");

                    var ccProps = ccLoadout.GetProperties();
                    ccProps.GetProp <ArrayProperty <StructProperty> >("ShieldLoadouts").Clear(); // Remove shields

                    // Set health to 1
                    var health = ccProps.GetProp <StructProperty>("MaxHealth");
                    health.GetProp <FloatProperty>("X").Value = 1;
                    health.GetProp <FloatProperty>("Y").Value = 1;

                    ccLoadout.WriteProperties(ccProps);

                    // Remove any passive powers
                    ZeroOutStatList(charClassP.FindExport($"SFXGameContent_Powers.SFXPower_{c}Passive"), "HealthBonus", false);
                    ZeroOutStatList(charClassP.FindExport($"SFXGameContent_Powers.SFXPower_{c}Passive_Evolved1"), "HealthBonus", false);
                    ZeroOutStatList(charClassP.FindExport($"SFXGameContent_Powers.SFXPower_{c}Passive_Evolved2"), "HealthBonus", false);

                    if (c == "Vanguard")
                    {
                        // Patch the immunity effect
                        var shieldEffectOnApplied = charClassP.GetUExport(530);
                        var seData = shieldEffectOnApplied.Data;
                        NopRange(seData, 0x2BF, 0x13);
                        shieldEffectOnApplied.Data = seData;
                    }

                    MERFileSystem.SavePackage(charClassP);
                }
            }

            // Zero out stats in tables
            MERPackageCache cache = new MERPackageCache();

            foreach (var asset in ZeroOutStatAssets)
            {
                var statClass = asset.GetAsset(cache);
                if (statClass != null)
                {
                    foreach (var zos in asset.PropertiesToZeroOut)
                    {
                        ZeroOutStatList(statClass, zos, true);
                    }
                }
            }

            foreach (var package in cache.GetPackages())
            {
                MERFileSystem.SavePackage(package);
            }

            {
                //var reaveF = MERFileSystem.GetPackageFile("SFXPower_Reave_Player.pcc");
                //if (reaveF != null && File.Exists(reaveF))
                //{
                //    var reaveP = MEPackageHandler.OpenMEPackage(reaveF);

                //    var defaultReave = reaveP.GetUExport(27);
                //    var regen = defaultReave.GetProperty<ArrayProperty<FloatProperty>>("HealthRegenMult");
                //    regen[0].Value = 0;
                //    regen[1].Value = 0;
                //    regen[2].Value = 0;
                //    regen[3].Value = 0;
                //    defaultReave.WriteProperty(regen);

                //    var bonusDuration = defaultReave.GetProperty<ArrayProperty<FloatProperty>>("HealthBonusDuration");
                //    bonusDuration[0].Value = 0;
                //    bonusDuration[1].Value = 0;
                //    bonusDuration[2].Value = 0;
                //    bonusDuration[3].Value = 0;
                //    defaultReave.WriteProperty(bonusDuration);

                //    MERFileSystem.SavePackage(reaveP);
                //}
            }

            return(true);
        }
        public static bool PortPawnIntoPackage(PortablePawn pawn, IMEPackage targetPackage)
        {
            if (IsPawnAssetInPackageAlready(pawn, targetPackage))
            {
                return(true); // Pawn asset to port in already ported in
            }

            IMEPackage pawnPackage = null;

            if (pawn.IsCorrectedPackage)
            {
                // DEBUG
                //if (pawn.PackageFilename == "BioPawn_Collector_Batarian.pcc")
                //{
                //    pawnPackage = MEPackageHandler.OpenMEPackage(@"C:\Users\mgame\source\repos\ME2Randomizer\ME2Randomizer\staticfiles\binary\correctedpawns\" + pawn.PackageFilename);
                //}
                //else
                //{
                var correctedPawnData = MERUtilities.GetEmbeddedStaticFilesBinaryFile($"correctedpawns.{pawn.PackageFilename}");
                pawnPackage = MEPackageHandler.OpenMEPackageFromStream(new MemoryStream(correctedPawnData));
                //}
            }
            else
            {
                var pF = MERFileSystem.GetPackageFile(pawn.PackageFilename);
                if (pF != null)
                {
                    pawnPackage = MERFileSystem.OpenMEPackage(pF);
                }
                else
                {
                    Debug.WriteLine("Pawn package not found: {pawn.PackageFilename}");
                }
            }

            if (pawnPackage != null)
            {
                PackageTools.PortExportIntoPackage(targetPackage, pawnPackage.FindExport(pawn.AssetToPortIn), useMemorySafeImport: !pawn.IsCorrectedPackage);

                // Ensure the assets are too as they may not be directly referenced except in the level instance
                foreach (var asset in pawn.AssetPaths)
                {
                    if (targetPackage.FindExport(asset) == null)
                    {
                        PackageTools.PortExportIntoPackage(targetPackage, pawnPackage.FindExport(asset), useMemorySafeImport: !pawn.IsCorrectedPackage);
                    }
                }

                if (pawn.TextureUpdates != null)
                {
                    foreach (var tu in pawn.TextureUpdates)
                    {
                        var targetTextureExp = targetPackage.FindExport(tu.TextureInstancedFullPath);
                        TFCBuilder.InstallTexture(tu, targetTextureExp);
                    }
                }

                return(true);
            }
            return(false);
        }
        public static IEntry PortWeaponIntoPackage(IMEPackage targetPackage, GunInfo gunInfo)
        {
            IMEPackage sourcePackage;

            if (gunInfo.IsCorrectedPackage)
            {
                var sourceData = MERUtilities.GetEmbeddedStaticFilesBinaryFile("correctedloadouts.weapons." + gunInfo.PackageFileName);
                sourcePackage = MEPackageHandler.OpenMEPackageFromStream(new MemoryStream(sourceData));

                if (gunInfo.ImportOnly)
                {
                    // We need to install this file
                    var outfname = Path.Combine(MERFileSystem.DLCModCookedPath, gunInfo.PackageFileName);
                    if (!File.Exists(outfname))
                    {
                        sourcePackage.Save(outfname, true);
                        ThreadSafeDLCStartupPackage.AddStartupPackage(Path.GetFileNameWithoutExtension(gunInfo.PackageFileName));
                    }
                }
            }
            else
            {
                sourcePackage = NonSharedPackageCache.Cache.GetCachedPackage(gunInfo.PackageFileName);
            }

            if (sourcePackage != null)
            {
                var sourceExport = sourcePackage.GetUExport(gunInfo.SourceUIndex);

                if (!sourceExport.InheritsFrom("SFXWeapon") || sourceExport.IsDefaultObject)
                {
                    throw new Exception("Wrong setup!");
                }

                if (sourceExport.Parent != null && sourceExport.Parent.ClassName != "Package")
                {
                    throw new Exception("Cannot port weapon - parent object is not Package!");
                }

                // 1. Setup the link that will be used.
                //var newParent = EntryExporter.PortParents(sourceExport, targetPackage);
                var newParent = EntryExporter.PortParents(sourceExport, targetPackage, gunInfo.ImportOnly);

                void errorOccuredCB(string s)
                {
                    Debugger.Break();
                }

                IEntry newEntry = null;
                if (gunInfo.ImportOnly)
                {
                    Debug.WriteLine($"Gun ImportOnly in file {targetPackage.FilePath}");
                    if (gunInfo.RequiresStartupPackage)
                    {
                        ThreadSafeDLCStartupPackage.AddStartupPackage(Path.GetFileNameWithoutExtension(gunInfo.PackageFileName));
                    }

                    newEntry = PackageTools.CreateImportForClass(sourceExport, targetPackage, newParent);
                }
                else
                {
                    List <EntryStringPair> relinkResults = null;
                    if (gunInfo.IsCorrectedPackage || (PackageTools.IsPersistentPackage(gunInfo.PackageFileName) && MERFileSystem.GetPackageFile(gunInfo.PackageFileName.ToLocalizedFilename()) == null))
                    {
                        // Faster this way, without having to check imports
                        Dictionary <IEntry, IEntry> crossPCCObjectMap = new Dictionary <IEntry, IEntry>(); // Not sure what this is used for these days. SHould probably just be part of the method
                        relinkResults = EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, sourceExport, targetPackage,
                                                                             newParent, true, out newEntry, crossPCCObjectMap);
                    }
                    else
                    {
                        // MEMORY SAFE (resolve imports to exports)
                        MERPackageCache cache = new MERPackageCache();
                        relinkResults = EntryExporter.ExportExportToPackage(sourceExport, targetPackage, out newEntry, cache);
                    }

                    if (relinkResults.Any())
                    {
                        Debugger.Break();
                    }
                }

                return(newEntry);
            }
            else
            {
                Debug.WriteLine($"Package for gun porting not found: {gunInfo.PackageFileName}");
            }
            return(null); // No package was found
        }
        /// <summary>
        /// Ports an export into a package. Checks if the export already exists, and if it does, returns that instead.
        /// </summary>
        /// <param name="targetPackage">The target package to port into.</param>
        /// <param name="sourceExport">The source export to port over, including all dependencies and references.</param>
        /// <param name="targetLink">The target link UIndex. Only used if createParentPackages is false.</param>
        /// <param name="createParentPackages">If the export should be ported in the same way as it was cooked into the package natively, e.g. create the parent package paths. The export must directly sit under a Package or an exception will be thrown.</param>
        /// <param name="ensureMemoryUniqueness">If this object is an instance, such as a sequence object, and should be made memory-unique so it is properly used</param>
        /// <returns></returns>
        public static ExportEntry PortExportIntoPackage(IMEPackage targetPackage, ExportEntry sourceExport, int targetLink = 0, bool createParentPackages = true, bool ensureMemoryUniqueness = false, bool useMemorySafeImport = false, PackageCache cache = null)
        {
#if DEBUG
            // in preprocessor to prevent this from running in release mode
            if (sourceExport.FileRef.FilePath != null && targetPackage.FilePath != null)
            {
                Debug.WriteLine($"Porting {sourceExport.InstancedFullPath} from {Path.GetFileName(sourceExport.FileRef.FilePath)} into {Path.GetFileName(targetPackage.FilePath)}");
            }
#endif
            var existing = targetPackage.FindExport(sourceExport.InstancedFullPath);
            if (existing != null)
            {
                return(existing);
            }

            // Create parent hierarchy
            IEntry newParent = null;
            if (createParentPackages)
            {
                List <IEntry> parents = new List <IEntry>();
                var           parent  = sourceExport.Parent;
                while (parent != null)
                {
                    if (parent.ClassName != "Package")
                    {
                        throw new Exception("Parent is not package!");
                    }
                    parents.Add(parent);
                    parent = parent.Parent;
                }

                // Create the parents
                parents.Reverse();
                foreach (var p in parents)
                {
                    var sourceFullPath = p.InstancedFullPath;
                    var matchingParent = targetPackage.FindEntry(sourceFullPath);

                    if (matchingParent != null)
                    {
                        newParent = matchingParent;
                        continue;
                    }

                    newParent = ExportCreator.CreatePackageExport(targetPackage, p.ObjectName, newParent);
                }
            }
            else
            {
                newParent = targetPackage.GetEntry(targetLink);
            }


            IEntry newEntry;
            if (!useMemorySafeImport)
            {
                Dictionary <IEntry, IEntry> crossPCCObjectMap = new Dictionary <IEntry, IEntry>(); // Not sure what this is used for these days. Should probably just be part of the method
                var relinkResults = EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, sourceExport, targetPackage,
                                                                         newParent, true, out newEntry, crossPCCObjectMap);
                if (relinkResults.Any())
                {
                    Debugger.Break();
                }
            }
            else
            {
                // Memory safe, fixes upstream
                var relinkedResults = EntryExporter.ExportExportToPackage(sourceExport, targetPackage, out newEntry, MERFileSystem.GetGlobalCache(), cache);
                if (relinkedResults.Any())
                {
                    Debugger.Break();
                }
            }
#if DEBUG
            //(sourceExport.FileRef as MEPackage).CompareToPackageDetailed(targetPackage);
#endif

            // Helps ensure we don't have memory duplicates
            if (ensureMemoryUniqueness)
            {
                newEntry.ObjectName = targetPackage.GetNextIndexedName(newEntry.ObjectName);
            }

            return(newEntry as ExportEntry);
        }
        private static void RandomizeAsteroidRelayColor()
        {
            // Relay at the end of the DLC
            var shuttleFile = MERFileSystem.GetPackageFile(@"BioD_ArvLvl5_110_Asteroid.pcc", false);

            if (shuttleFile != null && File.Exists(shuttleFile))
            {
                var shuttleP   = MEPackageHandler.OpenMEPackage(shuttleFile);
                var randColorR = ThreadSafeRandom.Next(256);
                var randColorG = ThreadSafeRandom.Next(256);
                var randColorB = ThreadSafeRandom.Next(256);

                var stringsGlowMatInst = shuttleP.GetUExport(170);
                var props       = stringsGlowMatInst.GetProperties();
                var linearColor = props.GetProp <ArrayProperty <StructProperty> >("VectorParameterValues")[0].GetProp <StructProperty>("ParameterValue");
                linearColor.GetProp <FloatProperty>("R").Value = randColorR;
                linearColor.GetProp <FloatProperty>("G").Value = randColorG;
                linearColor.GetProp <FloatProperty>("B").Value = randColorB;
                stringsGlowMatInst.WriteProperties(props);

                var lensFlare   = shuttleP.GetUExport(97);
                var sourceColor = lensFlare.GetProperty <StructProperty>("SourceColor");
                sourceColor.GetProp <FloatProperty>("R").Value = randColorR / 90.0f;
                sourceColor.GetProp <FloatProperty>("G").Value = randColorG / 90.0f;
                sourceColor.GetProp <FloatProperty>("B").Value = randColorB / 90.0f;
                lensFlare.WriteProperty(sourceColor);

                // lighting on the relay
                var pointlight      = shuttleP.GetUExport(710);
                var pointlightColor = pointlight.GetProperty <StructProperty>("LightColor");
                var lightR          = randColorR / 2 + 170;
                var lightG          = randColorG / 2 + 170;
                var lightB          = randColorB / 2 + 170;
                pointlightColor.GetProp <ByteProperty>("R").Value = (byte)lightR;
                pointlightColor.GetProp <ByteProperty>("G").Value = (byte)lightG;
                pointlightColor.GetProp <ByteProperty>("B").Value = (byte)lightB;
                pointlight.WriteProperty(pointlightColor);

                //Shield Impact Ring (?)
                var sir  = shuttleP.GetUExport(112);
                var data = sir.Data;
                data.OverwriteRange(0x418, BitConverter.GetBytes(randColorR / 80.0f));
                data.OverwriteRange(0x41C, BitConverter.GetBytes(randColorG / 80.0f));
                data.OverwriteRange(0x420, BitConverter.GetBytes(randColorB / 80.0f));
                sir.Data = data;

                //Particle effect
                var pe = shuttleP.GetUExport(339);
                props = pe.GetProperties();
                var     lookupTable = props.GetProp <StructProperty>("ColorOverLife").GetProp <ArrayProperty <FloatProperty> >("LookupTable");
                float[] allColors   = { randColorR / 255.0f, randColorG / 255.0f, randColorB / 255.0f };
                lookupTable.Clear();
                lookupTable.Add(new FloatProperty(allColors.Min()));
                lookupTable.Add(new FloatProperty(allColors.Max()));

                lookupTable.Add(new FloatProperty(allColors[0])); //r
                lookupTable.Add(new FloatProperty(allColors[1])); //g
                lookupTable.Add(new FloatProperty(allColors[2])); //b

                int numToAdd = ThreadSafeRandom.Next(3);

                //flare brightens as it fades out
                lookupTable.Add(new FloatProperty(allColors[0] + numToAdd == 0 ? .3f : 0f)); //r
                lookupTable.Add(new FloatProperty(allColors[1] + numToAdd == 1 ? .3f : 0f)); //g
                lookupTable.Add(new FloatProperty(allColors[2] + numToAdd == 2 ? .3f : 0f)); //b
                pe.WriteProperties(props);

                MERFileSystem.SavePackage(shuttleP);
            }
            else
            {
                MERLog.Information(@"BioD_ArvLvl5_110_Asteroid not found, skipping...");
            }

            // Relay shown in the shuttle at the end of act 1
            var asteroidf = MERFileSystem.GetPackageFile(@"BioD_ArvLvl1_710Shuttle.pcc", false);

            if (asteroidf != null && File.Exists(asteroidf))
            {
                var skhuttleP  = MEPackageHandler.OpenMEPackage(asteroidf);
                var randColorR = ThreadSafeRandom.Next(256);
                var randColorG = ThreadSafeRandom.Next(256);
                var randColorB = ThreadSafeRandom.Next(256);

                var stringsGlowMatInst = skhuttleP.GetUExport(4715); //strings glow
                var props       = stringsGlowMatInst.GetProperties();
                var linearColor = props.GetProp <ArrayProperty <StructProperty> >("VectorParameterValues")[0].GetProp <StructProperty>("ParameterValue");
                linearColor.GetProp <FloatProperty>("R").Value = randColorR;
                linearColor.GetProp <FloatProperty>("G").Value = randColorG;
                linearColor.GetProp <FloatProperty>("B").Value = randColorB;
                stringsGlowMatInst.WriteProperties(props);

                var lensFlare   = skhuttleP.GetUExport(2230);
                var sourceColor = lensFlare.GetProperty <StructProperty>("SourceColor");
                sourceColor.GetProp <FloatProperty>("R").Value = randColorR / 90.0f;
                sourceColor.GetProp <FloatProperty>("G").Value = randColorG / 90.0f;
                sourceColor.GetProp <FloatProperty>("B").Value = randColorB / 90.0f;
                lensFlare.WriteProperty(sourceColor);

                // lighting on the relay
                var pointlight      = skhuttleP.GetUExport(8425);
                var pointlightColor = pointlight.GetProperty <StructProperty>("LightColor");
                var lightR          = randColorR / 2 + 170;
                var lightG          = randColorG / 2 + 170;
                var lightB          = randColorB / 2 + 170;
                pointlightColor.GetProp <ByteProperty>("R").Value = (byte)lightR;
                pointlightColor.GetProp <ByteProperty>("G").Value = (byte)lightG;
                pointlightColor.GetProp <ByteProperty>("B").Value = (byte)lightB;
                pointlight.WriteProperty(pointlightColor);

                //Shield Impact Ring (?)
                var sir  = skhuttleP.GetUExport(2278);
                var data = sir.Data;
                data.OverwriteRange(0x418, BitConverter.GetBytes(randColorR / 80.0f));
                data.OverwriteRange(0x41C, BitConverter.GetBytes(randColorG / 80.0f));
                data.OverwriteRange(0x420, BitConverter.GetBytes(randColorB / 80.0f));
                sir.Data = data;

                //Particle effect
                var pe = skhuttleP.GetUExport(6078);
                props = pe.GetProperties();
                var     lookupTable = props.GetProp <StructProperty>("ColorOverLife").GetProp <ArrayProperty <FloatProperty> >("LookupTable");
                float[] allColors   = { randColorR / 255.0f, randColorG / 255.0f, randColorB / 255.0f };
                lookupTable.Clear();
                lookupTable.Add(new FloatProperty(allColors.Min()));
                lookupTable.Add(new FloatProperty(allColors.Max()));

                lookupTable.Add(new FloatProperty(allColors[0])); //r
                lookupTable.Add(new FloatProperty(allColors[1])); //g
                lookupTable.Add(new FloatProperty(allColors[2])); //b

                int numToAdd = ThreadSafeRandom.Next(3);

                //flare brightens as it fades out
                lookupTable.Add(new FloatProperty(allColors[0] + numToAdd == 0 ? .3f : 0f)); //r
                lookupTable.Add(new FloatProperty(allColors[1] + numToAdd == 1 ? .3f : 0f)); //g
                lookupTable.Add(new FloatProperty(allColors[2] + numToAdd == 2 ? .3f : 0f)); //b
                pe.WriteProperties(props);

                MERFileSystem.SavePackage(skhuttleP);
            }
            else
            {
                MERLog.Information(@"BioD_ArvLvl1_710Shuttle not found, skipping...");
            }
        }
        public static bool RandomizeCharacterCreator(RandomizationOption option)
        {
            var biop_charF         = MERFileSystem.GetPackageFile(@"BioP_Char.pcc");
            var biop_char          = MEPackageHandler.OpenMEPackage(biop_charF);
            var maleFrontEndData   = biop_char.GetUExport(18753);
            var femaleFrontEndData = biop_char.GetUExport(18754);

            var codeMapMale   = CalculateCodeMap(maleFrontEndData);
            var codeMapFemale = CalculateCodeMap(femaleFrontEndData);

            var bioUI                  = CoalescedHandler.GetIniFile("BIOUI.ini");
            var bgr                    = CoalescedHandler.GetIniFile("BIOGuiResources.ini");
            var charCreatorPCS         = bgr.GetOrAddSection("SFXGame.BioSFHandler_PCNewCharacter");
            var charCreatorControllerS = bioUI.GetOrAddSection("SFXGame.BioSFHandler_NewCharacter");

            charCreatorPCS.Entries.Add(new DuplicatingIni.IniEntry("!MalePregeneratedHeadCodes", "CLEAR"));
            charCreatorControllerS.Entries.Add(new DuplicatingIni.IniEntry("!MalePregeneratedHeadCodes", "CLEAR"));

            int numToMake = 20;
            int i         = 0;

            // Male: 34 chars
            while (i < numToMake)
            {
                i++;
                charCreatorPCS.Entries.Add(GenerateHeadCode(codeMapMale, false));
                charCreatorControllerS.Entries.Add(GenerateHeadCode(codeMapMale, false));
            }



            // Female: 36 chars
            charCreatorPCS.Entries.Add(new DuplicatingIni.IniEntry(""));         //blank line
            charCreatorControllerS.Entries.Add(new DuplicatingIni.IniEntry("")); //blank line
            charCreatorPCS.Entries.Add(new DuplicatingIni.IniEntry("!FemalePregeneratedHeadCodes", "CLEAR"));
            charCreatorControllerS.Entries.Add(new DuplicatingIni.IniEntry("!FemalePregeneratedHeadCodes", "CLEAR"));
            charCreatorPCS.Entries.Add(new DuplicatingIni.IniEntry("!FemalePregeneratedHeadCodes", "CLEAR"));

            i = 0;
            while (i < numToMake)
            {
                i++;
                charCreatorPCS.Entries.Add(GenerateHeadCode(codeMapFemale, true));
                charCreatorControllerS.Entries.Add(GenerateHeadCode(codeMapFemale, true));
            }


            randomizeFrontEnd(maleFrontEndData);
            randomizeFrontEnd(femaleFrontEndData);


            //Copy the final skeleton from female into male.
            var femBase  = biop_char.GetUExport(3480);
            var maleBase = biop_char.GetUExport(3481);

            maleBase.WriteProperty(femBase.GetProperty <ArrayProperty <StructProperty> >("m_aFinalSkeleton"));

            var randomizeColors = !option.HasSubOptionSelected(CharacterCreator.SUBOPTIONKEY_CHARCREATOR_NO_COLORS);

            foreach (var export in biop_char.Exports)
            {
                if (export.ClassName == "BioMorphFace" && !export.ObjectName.Name.Contains("Iconic"))
                {
                    RBioMorphFace.RandomizeExportNonHench(export, SuperRandomOption); //.3 default
                }
                else if (export.ClassName == "MorphTarget")
                {
                    if (
                        export.ObjectName.Name.StartsWith("jaw") || export.ObjectName.Name.StartsWith("mouth") ||
                        export.ObjectName.Name.StartsWith("eye") ||
                        export.ObjectName.Name.StartsWith("cheek") ||
                        export.ObjectName.Name.StartsWith("nose") ||
                        export.ObjectName.Name.StartsWith("teeth")
                        )
                    {
                        RMorphTarget.RandomizeExport(export, option);
                    }
                }
                else if (export.ClassName == "BioMorphFaceFESliderColour" && randomizeColors)
                {
                    var colors = export.GetProperty <ArrayProperty <StructProperty> >("m_acColours");
                    foreach (var color in colors)
                    {
                        RStructs.RandomizeColor(color, true, .5, 1.5);
                    }
                    export.WriteProperty(colors);
                }
                else if (export.ClassName == "BioMorphFaceFESliderMorph")
                {
                    // These don't work becuase of the limits in the morph system
                    // So all this does is change how much the values change, not the max/min
                }
                else if (export.ClassName == "BioMorphFaceFESliderScalar" || export.ClassName == "BioMorphFaceFESliderSetMorph")
                {
                    //no idea how to randomize this lol
                    var floats   = export.GetProperty <ArrayProperty <FloatProperty> >("m_afValues");
                    var minfloat = floats.Min();
                    var maxfloat = floats.Max();
                    if (minfloat == maxfloat)
                    {
                        if (minfloat == 0)
                        {
                            maxfloat = 1;
                        }
                        else
                        {
                            var vari = minfloat / 2;
                            maxfloat = ThreadSafeRandom.NextFloat(-vari, vari) + minfloat; //+/- 50%
                        }
                    }
                    foreach (var floatval in floats)
                    {
                        floatval.Value = ThreadSafeRandom.NextFloat(minfloat, maxfloat);
                    }
                    export.WriteProperty(floats);
                }
                else if (export.ClassName == "BioMorphFaceFESliderTexture")
                {
                }
            }
            MERFileSystem.SavePackage(biop_char);
            return(true);
        }
Esempio n. 13
0
        private static int AddNewRandomizedMovementSpeed(ExportEntry bio_appr_character)
        {
            ImportEntry sfxMovementData = bio_appr_character.FileRef.FindImport("SFXGame.SFXMovementData");

            if (sfxMovementData == null)
            {
                // Import needs added

                // ME2 SPECIFIC!
                sfxMovementData = EntryImporter.GetOrAddCrossImportOrPackageFromGlobalFile("SFXMovementData", MEPackageHandler.OpenMEPackage(MERFileSystem.GetPackageFile("SFXGame.pcc")), bio_appr_character.FileRef) as ImportEntry;
            }

            PropertyCollection props = new PropertyCollection();

            props.Add(new FloatProperty(ThreadSafeRandom.NextFloat(70, 210) + (ThreadSafeRandom.Next(10) == 0 ? 100 : 0), "WalkSpeed"));
            props.Add(new FloatProperty(ThreadSafeRandom.NextFloat(200, 700) + (ThreadSafeRandom.Next(10) == 0 ? 100 : 0), "GroundSpeed"));
            props.Add(new FloatProperty(ThreadSafeRandom.NextFloat(50, 900) + (ThreadSafeRandom.Next(10) == 0 ? 100 : 0), "TurnSpeed"));
            props.Add(new FloatProperty(ThreadSafeRandom.NextFloat(100, 320) + (ThreadSafeRandom.Next(10) == 0 ? 100 : 0), "CombatWalkSpeed"));
            props.Add(new FloatProperty(ThreadSafeRandom.NextFloat(10, 470) + (ThreadSafeRandom.Next(10) == 0 ? 100 : 0), "CombatGroundSpeed"));
            props.Add(new FloatProperty(ThreadSafeRandom.NextFloat(100, 380) + (ThreadSafeRandom.Next(10) == 0 ? 100 : 0), "CoverGroundSpeed"));
            props.Add(new FloatProperty(ThreadSafeRandom.NextFloat(60, 180) + (ThreadSafeRandom.Next(10) == 0 ? 100 : 0), "CoverCrouchGroundSpeed"));
            props.Add(new FloatProperty(ThreadSafeRandom.NextFloat(300, 900) + (ThreadSafeRandom.Next(10) == 0 ? 100 : 0), "StormSpeed"));
            props.Add(new FloatProperty(ThreadSafeRandom.NextFloat(25, 75) + (ThreadSafeRandom.Next(10) == 0 ? 20 : 0), "StormTurnSpeed"));
            props.Add(new FloatProperty(ThreadSafeRandom.NextFloat(250, 1250) + (ThreadSafeRandom.Next(10) == 0 ? 100 : 0), "AccelRate"));

            var export = new ExportEntry(bio_appr_character.FileRef, null, new NameReference("ME2RMovementData", ThreadSafeRandom.Next(200000)), properties: props)
            {
                Class   = sfxMovementData,
                idxLink = bio_appr_character.FileRef.Exports.First(x => x.ClassName == "Package").UIndex,
            };

            bio_appr_character.FileRef.AddExport(export);
            return(export.UIndex);
        }
Esempio n. 14
0
        /// <summary>
        /// Technically this is not part of Nor (It's EndGm). But it takes place on normandy so users
        /// will think it is part of the normandy.
        /// </summary>
        /// <param name="random"></param>
        private static void RandomizeRomance()
        {
            // Romance is 2 pass:

            // Pass 1: The initial chances that are not ME1 or Miranda
            {
                var romChooserPackage = MEPackageHandler.OpenMEPackage(MERFileSystem.GetPackageFile("BioD_EndGm1_110Romance.pcc"));
                var romSeq            = romChooserPackage.GetUExport(88);
                var outToRepoint      = romChooserPackage.GetUExport(65); //repoint to our switch

                // Install random switch and point it at the romance log culminations for each
                // Miranda gets 2 as she has a 50/50 of miranda or lonely shep.
                var randomSwitch = MERSeqTools.InstallRandomSwitchIntoSequence(romSeq, 7);
                var outLinks     = SeqTools.GetOutboundLinksOfNode(randomSwitch);

                outLinks[0].Add(new SeqTools.OutboundLink()
                {
                    InputLinkIdx = 0, LinkedOp = romChooserPackage.GetUExport(28)
                });                                                                                                             // JACOB
                outLinks[1].Add(new SeqTools.OutboundLink()
                {
                    InputLinkIdx = 0, LinkedOp = romChooserPackage.GetUExport(20)
                });                                                                                                             // GARRUS
                outLinks[2].Add(new SeqTools.OutboundLink()
                {
                    InputLinkIdx = 0, LinkedOp = romChooserPackage.GetUExport(30)
                });                                                                                                             // TALI
                outLinks[3].Add(new SeqTools.OutboundLink()
                {
                    InputLinkIdx = 0, LinkedOp = romChooserPackage.GetUExport(29)
                });                                                                                                             // THANE
                outLinks[4].Add(new SeqTools.OutboundLink()
                {
                    InputLinkIdx = 0, LinkedOp = romChooserPackage.GetUExport(27)
                });                                                                                                             // JACK
                outLinks[5].Add(new SeqTools.OutboundLink()
                {
                    InputLinkIdx = 0, LinkedOp = romChooserPackage.GetUExport(52)
                });                                                                                                             // MIRANDA--| -> Delay into teleport
                outLinks[6].Add(new SeqTools.OutboundLink()
                {
                    InputLinkIdx = 0, LinkedOp = romChooserPackage.GetUExport(52)
                });                                                                                                             // ME1------| -> Delay into teleport

                SeqTools.WriteOutboundLinksToNode(randomSwitch, outLinks);

                // Repoint to our randomswitch
                var penultimateOutbound = SeqTools.GetOutboundLinksOfNode(outToRepoint);
                penultimateOutbound[0].Clear();
                penultimateOutbound[0].Add(new SeqTools.OutboundLink()
                {
                    InputLinkIdx = 0, LinkedOp = randomSwitch
                });

                // DEBUG ONLY: FORCE LINK
                //penultimateOutbound[0].Add(new SeqTools.OutboundLink() { InputLinkIdx = 0, LinkedOp = romChooserPackage.GetUExport(27) });
                SeqTools.WriteOutboundLinksToNode(outToRepoint, penultimateOutbound);

                MERFileSystem.SavePackage(romChooserPackage);
            }

            // Pass 2: ME1 or Miranda if Pass 1 fell through at runtime
            {
                var romChooserPackage = MEPackageHandler.OpenMEPackage(MERFileSystem.GetPackageFile("BioD_EndGm1_110ROMMirranda.pcc"));
                var romSeq            = romChooserPackage.GetUExport(8468);
                var outToRepoint      = romChooserPackage.GetUExport(2354); //repoint to our switch

                // Install random switch and point it at the romance log culminations for each
                // Miranda gets 2 as she has a 50/50 of miranda or lonely shep.
                var randomSwitch = MERSeqTools.InstallRandomSwitchIntoSequence(romSeq, 2);
                var outLinks     = SeqTools.GetOutboundLinksOfNode(randomSwitch);

                outLinks[0].Add(new SeqTools.OutboundLink()
                {
                    InputLinkIdx = 0, LinkedOp = romChooserPackage.GetUExport(8432)
                });                                                                                                             // MIRANDA
                outLinks[1].Add(new SeqTools.OutboundLink()
                {
                    InputLinkIdx = 0, LinkedOp = romChooserPackage.GetUExport(8413)
                });                                                                                                             // ME1

                SeqTools.WriteOutboundLinksToNode(randomSwitch, outLinks);

                // Repoint to our randomswitch
                var penultimateOutbound = SeqTools.GetOutboundLinksOfNode(outToRepoint);
                penultimateOutbound[0].Clear();
                penultimateOutbound[0].Add(new SeqTools.OutboundLink()
                {
                    InputLinkIdx = 0, LinkedOp = randomSwitch
                });
                SeqTools.WriteOutboundLinksToNode(outToRepoint, penultimateOutbound);

                MERFileSystem.SavePackage(romChooserPackage);
            }
        }