using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem.Collections.Generic; using Microsoft.CodeAnalysis; using SOD.Common; using SOD.Common.Helpers.SyncDiskObjects; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SoDVanillaSplit")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.4.0.0")] [assembly: AssemblyInformationalVersion("0.4.0")] [assembly: AssemblyProduct("SoDVanillaSplit")] [assembly: AssemblyTitle("SoDVanillaSplit")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.4.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SoDVanillaSplit { [BepInPlugin("ta.sod.vanillasplit", "SoD Vanilla Split", "0.4.0")] public class Plugin : BasePlugin { public const string GUID = "ta.sod.vanillasplit"; internal static ManualLogSource L; internal static ConfigEntry RemoveParents; internal static ConfigEntry ClearParentSpawnData; internal static ConfigEntry SaleLocation; internal static readonly Dictionary Made = new Dictionary(); internal static readonly Dictionary Defs = new Dictionary(); internal static readonly Dictionary Prices = new Dictionary(); public override void Load() { L = ((BasePlugin)this).Log; L.LogInfo((object)"=== SoDVanillaSplit 0.4.0 starting ==="); RemoveParents = ((BasePlugin)this).Config.Bind("General", "RemoveVanillaParents", false, "Remove the 17 split parent presets from Toolbox.allSyncDisks so only the split disks are sold. Starch-SugarDaddy is never removed. Leave false to run the splits ALONGSIDE vanilla."); ClearParentSpawnData = ((BasePlugin)this).Config.Bind("General", "ClearParentSpawnData", true, "Also clear occupation and trait spawn data on the removed parents. Toolbox removal alone suppresses vendor stock but NOT world loot: a combined parent can still be found in the world. Only applies when RemoveVanillaParents is true."); SaleLocation = ((BasePlugin)this).Config.Bind("General", "SaleLocation", "SyncClinic", "Menu preset the split disks are added to. Blank for none."); string loc = ((SaleLocation.Value == null) ? "" : SaleLocation.Value.Trim()); int num = 0; SplitDef[] all = Splits.All; foreach (SplitDef splitDef in all) { if (!((BasePlugin)this).Config.Bind(splitDef.Parent, splitDef.DiskName, true, "Register this split disk.").Value) { L.LogInfo((object)("skipped: " + splitDef.DiskName)); continue; } Prices[splitDef.DiskName] = ((BasePlugin)this).Config.Bind(splitDef.Parent, splitDef.DiskName + " price", splitDef.Price, "Credits. Split disks are priced for what the branch does, not what the parent cost, so a set of splits costs more in total than the disk they came from. Price is not a save key and can be changed on a live save.").Value; try { Register(splitDef, loc); num++; } catch (Exception ex) { L.LogError((object)("FAILED to register " + splitDef.DiskName + ": " + ex)); } } Harmony.CreateAndPatchAll(typeof(SplitPatch), (string)null); L.LogInfo((object)("=== SoDVanillaSplit phase 1 done, " + num + " of " + Splits.All.Length + " registered ===")); } private static void Register(SplitDef d, string loc) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) int num = default(int); SyncDiskBuilder val = Lib.SyncDisks.Builder(d.DiskName, "ta.sod.vanillasplit", true).AddEffect(d.DiskName, "Pending vanilla data.", ref num, (string)null); if (loc.Length > 0) { val.AddSaleLocation(new string[1] { loc }); } if (d.Tiers > 0) { string text = d.DiskName + " upgrade one."; string text2 = d.DiskName + " upgrade two."; string text3 = d.DiskName + " upgrade three."; Options val2 = default(Options); if (d.Tiers == 1) { ((Options)(ref val2))..ctor(text); } else if (d.Tiers == 2) { ((Options)(ref val2))..ctor(text, text2); } else { ((Options)(ref val2))..ctor(text, text2, text3); } OptionIds val3 = default(OptionIds); val.AddUpgradeOption(val2, ref val3); } SyncDiskPreset preset = val.CreateAndRegister().Preset; preset.mainEffect2 = (Effect)0; preset.mainEffect2Value = 0f; preset.mainEffect3 = (Effect)0; preset.mainEffect3Value = 0f; Made[d.DiskName] = preset; Defs[d.DiskName] = d; L.LogInfo((object)("shell registered: " + d.DiskName + " <- " + d.Parent + " branch " + d.Branch + " tiers " + d.Tiers + " customId " + num)); } } [HarmonyPatch(typeof(Toolbox), "Start")] public static class SplitPatch { [HarmonyPatch(typeof(InteriorCreator), "StartLoading")] public static class LootRemovePatch { private static void Prefix() { if (!Plugin.RemoveParents.Value) { return; } Toolbox instance = Toolbox.Instance; List val = ((instance != null) ? instance.allSyncDisks : null); if (val == null) { return; } int num = 0; for (int num2 = val.Count - 1; num2 >= 0; num2--) { SyncDiskPreset val2 = val[num2]; if (!((SoCustomComparison)(object)val2 == (SoCustomComparison)null)) { string[] parents = Splits.Parents; foreach (string text in parents) { if (((Object)val2).name == text) { val.RemoveAt(num2); num++; break; } } } } if (num > 0) { Plugin.L.LogInfo((object)("=== LOOT PASS: removed " + num + " parents at chunk generation ===")); } } } private static bool done; private static void Postfix() { if (!done) { done = true; Dictionary parents = Index(); Copy(parents); Remove(parents); } } private static Dictionary Index() { Dictionary dictionary = new Dictionary(); List allSyncDisks = Toolbox.Instance.allSyncDisks; if (allSyncDisks == null) { Plugin.L.LogError((object)"=== Toolbox.allSyncDisks is null, phase 2 aborted ==="); return dictionary; } Enumerator enumerator = allSyncDisks.GetEnumerator(); while (enumerator.MoveNext()) { SyncDiskPreset current = enumerator.Current; if ((SoCustomComparison)(object)current == (SoCustomComparison)null) { continue; } string[] parents = Splits.Parents; foreach (string text in parents) { if (((Object)current).name == text && !dictionary.ContainsKey(text)) { dictionary[text] = current; } } } Plugin.L.LogInfo((object)("=== indexed " + dictionary.Count + " of " + Splits.Parents.Length + " parent presets ===")); return dictionary; } private static void Copy(Dictionary parents) { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0465: Unknown result type (might be due to invalid IL or missing references) //IL_046a: Unknown result type (might be due to invalid IL or missing references) //IL_04a1: Unknown result type (might be due to invalid IL or missing references) //IL_04a6: Unknown result type (might be due to invalid IL or missing references) //IL_04e0: Unknown result type (might be due to invalid IL or missing references) //IL_04e5: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_03d9: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) int num = 0; int num2 = 0; foreach (KeyValuePair item in Plugin.Made) { SyncDiskPreset value = item.Value; SplitDef splitDef = Plugin.Defs[item.Key]; if (!parents.TryGetValue(splitDef.Parent, out var value2) || (SoCustomComparison)(object)value2 == (SoCustomComparison)null) { Plugin.L.LogWarning((object)("parent NOT FOUND for " + splitDef.DiskName + " (" + splitDef.Parent + ") - disk left as placeholder")); num2++; continue; } value.price = (Plugin.Prices.TryGetValue(splitDef.DiskName, out var value3) ? value3 : value2.price); value.rarity = value2.rarity; value.manufacturer = value2.manufacturer; value.uninstallCost = value2.uninstallCost; value.minimumWealthLevel = value2.minimumWealthLevel; value.canBeSideJobReward = value2.canBeSideJobReward; value.sideEffect = value2.sideEffect; value.sideEffectValue = value2.sideEffectValue; value.sideEffectDescription = value2.sideEffectDescription; if (splitDef.Branch == 1) { value.mainEffect1 = value2.mainEffect1; value.mainEffect1Value = value2.mainEffect1Value; value.mainEffect1Description = value2.mainEffect1Description; value.mainEffect1Icon = value2.mainEffect1Icon; List option1UpgradeEffects = value2.option1UpgradeEffects; List option1UpgradeValues = value2.option1UpgradeValues; List option1UpgradeNameReferences = value2.option1UpgradeNameReferences; List option1UpgradeEffects2 = value.option1UpgradeEffects; List option1UpgradeValues2 = value.option1UpgradeValues; List option1UpgradeNameReferences2 = value.option1UpgradeNameReferences; for (int i = 0; i < splitDef.Tiers && i < option1UpgradeEffects.Count && i < option1UpgradeEffects2.Count; i++) { option1UpgradeEffects2[i] = Fix(option1UpgradeEffects[i], splitDef, i); option1UpgradeValues2[i] = option1UpgradeValues[i]; if (i < option1UpgradeNameReferences.Count && i < option1UpgradeNameReferences2.Count) { option1UpgradeNameReferences2[i] = option1UpgradeNameReferences[i]; } } } else if (splitDef.Branch == 2) { value.mainEffect1 = value2.mainEffect2; value.mainEffect1Value = value2.mainEffect2Value; value.mainEffect1Description = value2.mainEffect2Description; value.mainEffect1Icon = value2.mainEffect2Icon; List option2UpgradeEffects = value2.option2UpgradeEffects; List option2UpgradeValues = value2.option2UpgradeValues; List option2UpgradeNameReferences = value2.option2UpgradeNameReferences; List option1UpgradeEffects3 = value.option1UpgradeEffects; List option1UpgradeValues3 = value.option1UpgradeValues; List option1UpgradeNameReferences3 = value.option1UpgradeNameReferences; for (int j = 0; j < splitDef.Tiers && j < option2UpgradeEffects.Count && j < option1UpgradeEffects3.Count; j++) { option1UpgradeEffects3[j] = Fix(option2UpgradeEffects[j], splitDef, j); option1UpgradeValues3[j] = option2UpgradeValues[j]; if (j < option2UpgradeNameReferences.Count && j < option1UpgradeNameReferences3.Count) { option1UpgradeNameReferences3[j] = option2UpgradeNameReferences[j]; } } } else { value.mainEffect1 = value2.mainEffect3; value.mainEffect1Value = value2.mainEffect3Value; value.mainEffect1Description = value2.mainEffect3Description; value.mainEffect1Icon = value2.mainEffect3Icon; List option3UpgradeEffects = value2.option3UpgradeEffects; List option3UpgradeValues = value2.option3UpgradeValues; List option3UpgradeNameReferences = value2.option3UpgradeNameReferences; List option1UpgradeEffects4 = value.option1UpgradeEffects; List option1UpgradeValues4 = value.option1UpgradeValues; List option1UpgradeNameReferences4 = value.option1UpgradeNameReferences; for (int k = 0; k < splitDef.Tiers && k < option3UpgradeEffects.Count && k < option1UpgradeEffects4.Count; k++) { option1UpgradeEffects4[k] = Fix(option3UpgradeEffects[k], splitDef, k); option1UpgradeValues4[k] = option3UpgradeValues[k]; if (k < option3UpgradeNameReferences.Count && k < option1UpgradeNameReferences4.Count) { option1UpgradeNameReferences4[k] = option3UpgradeNameReferences[k]; } } } num++; Plugin.L.LogInfo((object)("copied " + splitDef.DiskName + " | effect=" + ((object)value.mainEffect1/*cast due to .constrained prefix*/).ToString() + " value=" + value.mainEffect1Value + " mfr=" + ((object)value.manufacturer/*cast due to .constrained prefix*/).ToString() + " price=" + value.price + " side=" + ((object)value.sideEffect/*cast due to .constrained prefix*/).ToString() + " tiers=" + splitDef.Tiers)); } Plugin.L.LogInfo((object)("=== copy pass complete: " + num + " copied, " + num2 + " missing parents ===")); } private static UpgradeEffect Fix(UpgradeEffect e, SplitDef d, int tier) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_004a: Unknown result type (might be due to invalid IL or missing references) if ((int)e == 2) { Plugin.L.LogInfo((object)("override: " + d.DiskName + " tier " + (tier + 1) + " bothConfigurations -> modifyEffect")); return (UpgradeEffect)1; } return e; } private static void ClearSpawnData(Dictionary parents) { if (!Plugin.ClearParentSpawnData.Value) { Plugin.L.LogInfo((object)"=== ClearParentSpawnData false, spawn data left intact ==="); return; } int num = 0; foreach (KeyValuePair parent in parents) { SyncDiskPreset value = parent.Value; if ((SoCustomComparison)(object)value == (SoCustomComparison)null) { continue; } try { int num2 = 0; int num3 = 0; try { if (value.occupation != null) { num2 = value.occupation.Count; } } catch { } try { if (value.traits != null) { num3 = value.traits.Count; } } catch { } if (value.occupation != null) { value.occupation.Clear(); } value.occupationWeight = 0; if (value.traits != null) { value.traits.Clear(); } value.traitWeight = 0; num++; Plugin.L.LogInfo((object)("=== SPAWN CLEARED: " + parent.Key + " occ " + num2 + "->0 traits " + num3 + "->0 ===")); } catch (Exception ex) { Plugin.L.LogError((object)("spawn clear FAILED for " + parent.Key + ": " + ex)); } } Plugin.L.LogInfo((object)("=== spawn clear complete: " + num + " of " + parents.Count + " parents ===")); } private static void Remove(Dictionary parents) { if (!Plugin.RemoveParents.Value) { Plugin.L.LogInfo((object)"=== RemoveVanillaParents false, parents left in place ==="); return; } ClearSpawnData(parents); int num = 0; List allSyncDisks = Toolbox.Instance.allSyncDisks; if (allSyncDisks != null) { for (int num2 = allSyncDisks.Count - 1; num2 >= 0; num2--) { SyncDiskPreset val = allSyncDisks[num2]; if (!((SoCustomComparison)(object)val == (SoCustomComparison)null)) { string[] parents2 = Splits.Parents; foreach (string text in parents2) { if (((Object)val).name == text) { allSyncDisks.RemoveAt(num2); num++; Plugin.L.LogInfo((object)("=== REMOVED from Toolbox.allSyncDisks: " + text + " ===")); break; } } } } } int num3 = 0; int num4 = 0; Il2CppArrayBase val2 = Resources.FindObjectsOfTypeAll(); if (val2 != null) { foreach (MenuPreset item in val2) { if ((SoCustomComparison)(object)item == (SoCustomComparison)null || item.syncDisks == null) { continue; } num4++; for (int num5 = item.syncDisks.Count - 1; num5 >= 0; num5--) { SyncDiskPreset val3 = item.syncDisks[num5]; if (!((SoCustomComparison)(object)val3 == (SoCustomComparison)null)) { string[] parents2 = Splits.Parents; foreach (string text2 in parents2) { if (((Object)val3).name == text2) { item.syncDisks.RemoveAt(num5); num3++; break; } } } } } } Plugin.L.LogInfo((object)("=== remove pass complete: " + num + " from Toolbox, " + num3 + " across " + num4 + " menu presets ===")); } } public class SplitDef { public string DiskName; public string Parent; public int Branch; public int Tiers; public int Price; } public static class Splits { public static readonly SplitDef[] All = new SplitDef[37] { new SplitDef { DiskName = "Clout", Parent = "ElGen-Tenacity", Branch = 1, Tiers = 3, Price = 1500 }, new SplitDef { DiskName = "Brawn", Parent = "ElGen-Tenacity", Branch = 2, Tiers = 3, Price = 1250 }, new SplitDef { DiskName = "Reflexes", Parent = "ElGen-Tenacity", Branch = 3, Tiers = 3, Price = 2500 }, new SplitDef { DiskName = "Lockpicker", Parent = "BlackMarket-Trespasser", Branch = 1, Tiers = 0, Price = 1750 }, new SplitDef { DiskName = "Resourceful", Parent = "BlackMarket-Trespasser", Branch = 2, Tiers = 0, Price = 1750 }, new SplitDef { DiskName = "Invisible", Parent = "BlackMarket-Trespasser", Branch = 3, Tiers = 0, Price = 1250 }, new SplitDef { DiskName = "Gold Medical Cover", Parent = "Kensington-SpartanInsuranceSchemes", Branch = 1, Tiers = 2, Price = 1000 }, new SplitDef { DiskName = "Gold Legal Cover", Parent = "Kensington-SpartanInsuranceSchemes", Branch = 2, Tiers = 2, Price = 1250 }, new SplitDef { DiskName = "Gold Accident Cover", Parent = "Kensington-SpartanInsuranceSchemes", Branch = 3, Tiers = 2, Price = 750 }, new SplitDef { DiskName = "Street Cleaner", Parent = "Candor-ModelCitizen", Branch = 1, Tiers = 3, Price = 500 }, new SplitDef { DiskName = "Bookworm", Parent = "Candor-ModelCitizen", Branch = 2, Tiers = 3, Price = 500 }, new SplitDef { DiskName = "Power", Parent = "ElGen-Vigor", Branch = 1, Tiers = 0, Price = 2500 }, new SplitDef { DiskName = "Stability", Parent = "ElGen-Vigor", Branch = 2, Tiers = 0, Price = 3000 }, new SplitDef { DiskName = "Physiological Perception", Parent = "Kaizen-DovePlus", Branch = 1, Tiers = 3, Price = 1750 }, new SplitDef { DiskName = "Socioeconomic Perception", Parent = "Kaizen-DovePlus", Branch = 2, Tiers = 3, Price = 1000 }, new SplitDef { DiskName = "Food Hygeine Inspector", Parent = "Candor-PublicService", Branch = 1, Tiers = 3, Price = 500 }, new SplitDef { DiskName = "Sanitary Hygeine Inspector", Parent = "Candor-PublicService", Branch = 2, Tiers = 3, Price = 500 }, new SplitDef { DiskName = "Rogue", Parent = "BlackMarket-Infiltrator", Branch = 1, Tiers = 1, Price = 1750 }, new SplitDef { DiskName = "Hacker", Parent = "BlackMarket-Infiltrator", Branch = 2, Tiers = 1, Price = 1750 }, new SplitDef { DiskName = "Cash Flow", Parent = "Kensington-AmbassadorScheme", Branch = 1, Tiers = 3, Price = 500 }, new SplitDef { DiskName = "Competitor Data Mining", Parent = "Kensington-AmbassadorScheme", Branch = 2, Tiers = 3, Price = 500 }, new SplitDef { DiskName = "Fortitude", Parent = "ElGen-Physique", Branch = 1, Tiers = 1, Price = 1750 }, new SplitDef { DiskName = "Vitality", Parent = "ElGen-Physique", Branch = 2, Tiers = 1, Price = 1500 }, new SplitDef { DiskName = "Allure", Parent = "ElGen-Beauty", Branch = 1, Tiers = 3, Price = 1500 }, new SplitDef { DiskName = "Charm", Parent = "ElGen-Beauty", Branch = 2, Tiers = 3, Price = 1500 }, new SplitDef { DiskName = "Chemistry", Parent = "ElGen-Constitution", Branch = 1, Tiers = 2, Price = 2000 }, new SplitDef { DiskName = "Cardiovascular", Parent = "ElGen-Constitution", Branch = 2, Tiers = 2, Price = 2000 }, new SplitDef { DiskName = "Spread the word!", Parent = "Starch-BrandAmbassador", Branch = 1, Tiers = 2, Price = 500 }, new SplitDef { DiskName = "Put some life into it!", Parent = "Starch-BrandAmbassador", Branch = 2, Tiers = 2, Price = 500 }, new SplitDef { DiskName = "Urbex Cartographer", Parent = "Candor-Cartographer", Branch = 1, Tiers = 0, Price = 500 }, new SplitDef { DiskName = "Crawlspace Engineer", Parent = "Candor-Cartographer", Branch = 2, Tiers = 0, Price = 500 }, new SplitDef { DiskName = "Care in the Community", Parent = "Candor-Community", Branch = 1, Tiers = 1, Price = 750 }, new SplitDef { DiskName = "Heavy Lifter", Parent = "Candor-Community", Branch = 2, Tiers = 1, Price = 1500 }, new SplitDef { DiskName = "Statuesque", Parent = "ElGen-Frame", Branch = 1, Tiers = 2, Price = 750 }, new SplitDef { DiskName = "Compact", Parent = "ElGen-Frame", Branch = 2, Tiers = 2, Price = 750 }, new SplitDef { DiskName = "Mailing List", Parent = "BlackMarket-Interceptor", Branch = 1, Tiers = 0, Price = 500 }, new SplitDef { DiskName = "Safecacker", Parent = "BlackMarket-Interceptor", Branch = 2, Tiers = 0, Price = 500 } }; public static readonly string[] Parents = new string[17] { "ElGen-Tenacity", "BlackMarket-Trespasser", "Kensington-SpartanInsuranceSchemes", "Candor-ModelCitizen", "ElGen-Vigor", "Kaizen-DovePlus", "Candor-PublicService", "BlackMarket-Infiltrator", "Kensington-AmbassadorScheme", "ElGen-Physique", "ElGen-Beauty", "ElGen-Constitution", "Starch-BrandAmbassador", "Candor-Cartographer", "Candor-Community", "ElGen-Frame", "BlackMarket-Interceptor" }; } }