using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("MoonsEqualised")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MoonsEqualised")] [assembly: AssemblyTitle("MoonsEqualised")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 MoonsEqualised { [BepInPlugin("jakov.moonsequalised", "Moons Equalised", "1.0.0")] public class Plugin : BaseUnityPlugin { private sealed class MoonConfig { public float FactorySizeMultiplier { get; } public int MinScrap { get; } public int MaxScrap { get; } public int MaxIndoorPower { get; } public int MaxOutdoorPower { get; } public int FacilityChance { get; } public int MineshaftChance { get; } public int MansionChance { get; } public MoonConfig(float factorySizeMultiplier, int minScrap, int maxScrap, int maxIndoorPower, int maxOutdoorPower, int facilityChance, int mineshaftChance, int mansionChance) { FactorySizeMultiplier = factorySizeMultiplier; MinScrap = minScrap; MaxScrap = maxScrap; MaxIndoorPower = maxIndoorPower; MaxOutdoorPower = maxOutdoorPower; FacilityChance = facilityChance; MineshaftChance = mineshaftChance; MansionChance = mansionChance; } } private static Harmony _harmony; private static ManualLogSource _log; private void Awake() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown if (_log == null) { _log = Logger.CreateLogSource("Moons Equalised"); } _log.LogInfo((object)"Moons Equalised awake."); if (_harmony == null) { _harmony = new Harmony("jakov.moonsequalised"); } try { PatchMethod(typeof(RoundManager), "LoadNewLevel", "RoundManager_LoadNewLevel_Prefix"); PatchMethod(typeof(Terminal), "LoadNewNode", "Terminal_LoadNewNode_Prefix", "Terminal_LoadNewNode_Postfix"); PatchMethod(typeof(Terminal), "LoadNewNodeIfAffordable", "Terminal_LoadNewNodeIfAffordable_Prefix", "Terminal_LoadNewNodeIfAffordable_Postfix"); _log.LogInfo((object)"Harmony patches applied successfully."); } catch (Exception arg) { _log.LogError((object)$"Failed to apply Harmony patches: {arg}"); } } private static void PatchMethod(Type targetType, string methodName, string patchName, string? postfixName = null) { //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Expected O, but got Unknown //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown MethodInfo method = targetType.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method == null) { _log.LogError((object)("Patch target not found: " + targetType.Name + "." + methodName)); return; } MethodInfo method2 = typeof(Plugin).GetMethod(patchName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method2 == null) { _log.LogError((object)("Patch method not found: " + patchName)); return; } HarmonyMethod val = null; if (!string.IsNullOrEmpty(postfixName)) { MethodInfo method3 = typeof(Plugin).GetMethod(postfixName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (method3 == null) { _log.LogError((object)("Patch postfix method not found: " + postfixName)); return; } val = new HarmonyMethod(method3); } _harmony.Patch((MethodBase)method, new HarmonyMethod(method2), val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _log.LogInfo((object)("Patched " + targetType.Name + "." + methodName + " with " + patchName + ((val != null) ? " + postfix" : string.Empty) + ".")); } private static void RoundManager_LoadNewLevel_Prefix(RoundManager __instance, int randomSeed, SelectableLevel newLevel) { try { if ((Object)(object)newLevel == (Object)null) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)"LoadNewLevel called with a null SelectableLevel."); } return; } ManualLogSource log2 = _log; if (log2 != null) { log2.LogInfo((object)("LoadNewLevel called for " + newLevel.PlanetName)); } ApplyLevelPatch(newLevel); ApplyDoorPricePatch(); } catch (Exception arg) { ManualLogSource log3 = _log; if (log3 != null) { log3.LogError((object)$"RoundManager_LoadNewLevel_Prefix error: {arg}"); } } } [HarmonyPatch(typeof(Terminal), "LoadNewNode")] [HarmonyPrefix] private static void Terminal_LoadNewNode_Prefix(Terminal __instance, TerminalNode node) { try { ApplyTerminalRoutePrice(node); } catch (Exception arg) { ManualLogSource log = _log; if (log != null) { log.LogError((object)$"Terminal_LoadNewNode_Prefix error: {arg}"); } } } private static void Terminal_LoadNewNode_Postfix(Terminal __instance) { try { if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.currentNode != (Object)null) { ApplyTerminalRoutePrice(__instance.currentNode); } } catch (Exception arg) { ManualLogSource log = _log; if (log != null) { log.LogError((object)$"Terminal_LoadNewNode_Postfix error: {arg}"); } } } [HarmonyPatch(typeof(Terminal), "LoadNewNodeIfAffordable")] [HarmonyPrefix] private static void Terminal_LoadNewNodeIfAffordable_Prefix(Terminal __instance, TerminalNode node) { try { ApplyTerminalRoutePrice(node); } catch (Exception arg) { ManualLogSource log = _log; if (log != null) { log.LogError((object)$"Terminal_LoadNewNodeIfAffordable_Prefix error: {arg}"); } } } private static void Terminal_LoadNewNodeIfAffordable_Postfix(Terminal __instance) { try { if ((Object)(object)__instance != (Object)null && (Object)(object)__instance.currentNode != (Object)null) { ApplyTerminalRoutePrice(__instance.currentNode); } } catch (Exception arg) { ManualLogSource log = _log; if (log != null) { log.LogError((object)$"Terminal_LoadNewNodeIfAffordable_Postfix error: {arg}"); } } } private static void ApplyLevelPatch(SelectableLevel level) { if ((Object)(object)level == (Object)null) { return; } Dictionary dictionary = new Dictionary { ["Experimentation"] = new MoonConfig(1.1f, 12, 15, 6, 9, 75, 25, 0), ["Assurance"] = new MoonConfig(1.2f, 13, 15, 6, 8, 65, 35, 0), ["Vow"] = new MoonConfig(1.1f, 12, 14, 7, 6, 50, 50, 0), ["Offense"] = new MoonConfig(1.5f, 17, 19, 10, 8, 0, 100, 0), ["March"] = new MoonConfig(1.3f, 16, 16, 14, 12, 85, 0, 15), ["Adamance"] = new MoonConfig(1.2f, 16, 18, 13, 11, 50, 50, 0), ["Rend"] = new MoonConfig(1.8f, 25, 29, 12, 6, 0, 0, 100), ["Dine"] = new MoonConfig(1.8f, 30, 30, 10, 9, 0, 20, 80), ["Titan"] = new MoonConfig(2.2f, 31, 33, 16, 7, 34, 33, 33), ["Artifice"] = new MoonConfig(1.8f, 27, 30, 12, 13, 60, 40, 0) }; string text = NormalizeMoonName(level.PlanetName); if (string.IsNullOrEmpty(text)) { return; } if (dictionary.TryGetValue(text, out var value)) { ApplyMoonConfig(level, value); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)("Patched " + text + " level values.")); } } if (text == "Dine") { ApplyDineLootPool(level); } } private static void ApplyDoorPricePatch() { Terminal val = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null || (Object)(object)val.terminalNodes == (Object)null) { return; } List terminalNodes = val.terminalNodes.terminalNodes; if (terminalNodes == null) { return; } foreach (TerminalNode item in terminalNodes) { ApplyTerminalRoutePrice(item); } } private static void ApplyTerminalRoutePrice(TerminalNode node) { if ((Object)(object)node == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.levels == null) { return; } SelectableLevel[] levels = StartOfRound.Instance.levels; foreach (SelectableLevel val in levels) { if ((Object)(object)val == (Object)null || node.buyRerouteToMoon != val.levelID) { continue; } string text = NormalizeMoonName(val.PlanetName); switch (text) { default: if (!(text == "Artifice")) { continue; } break; case "Rend": case "Dine": case "Titan": break; } node.itemCost = 1000; UpdateTerminalRouteUi(node, 1000); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)("Reroute cost set to 1000 for " + text + ".")); } } } private static void UpdateTerminalRouteUi(TerminalNode node, int newCost) { if ((Object)(object)node == (Object)null) { return; } if (!string.IsNullOrEmpty(node.displayText)) { node.displayText = ReplaceRouteCost(node.displayText, newCost); } Terminal val = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null) { return; } if (!string.IsNullOrEmpty(val.currentText)) { val.currentText = ReplaceRouteCost(val.currentText, newCost); } List list = new List(); if ((Object)(object)val.screenText != (Object)null) { list.Add((Object)(object)val.screenText); } if ((Object)(object)val.inputFieldText != (Object)null) { list.Add((Object)(object)val.inputFieldText); } if ((Object)(object)val.topRightText != (Object)null) { list.Add((Object)(object)val.topRightText); } TextMeshProUGUI[] array = Object.FindObjectsOfType(); foreach (TextMeshProUGUI val2 in array) { if ((Object)(object)val2 != (Object)null) { list.Add((Object)(object)val2); } } foreach (Object item in list) { if (item == (Object)null) { continue; } PropertyInfo property = ((object)item).GetType().GetProperty("text"); if (property == null || property.PropertyType != typeof(string)) { continue; } string text = property.GetValue(item) as string; if (!string.IsNullOrEmpty(text)) { string text2 = ReplaceRouteCost(text, newCost); if (!string.Equals(text, text2, StringComparison.Ordinal)) { property.SetValue(item, text2); } } } } private static string ReplaceRouteCost(string input, int newCost) { if (string.IsNullOrEmpty(input)) { return input; } return Regex.Replace(input, "(?i)(costs?\\s+)(\\d+)(\\s+credits?)", (Match match) => $"{match.Groups[1].Value}{newCost}{match.Groups[3].Value}"); } private static string NormalizeMoonName(string? moonName) { if (string.IsNullOrWhiteSpace(moonName)) { return string.Empty; } string text = moonName.Trim(); string[] array = text.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length > 1 && int.TryParse(array[0], out var _)) { return string.Join(" ", array, 1, array.Length - 1); } return text; } private static void ApplyMoonConfig(SelectableLevel level, MoonConfig config) { if (!((Object)(object)level == (Object)null)) { int minScrap = level.minScrap; int maxScrap = level.maxScrap; int minTotalScrapValue = level.minTotalScrapValue; int maxTotalScrapValue = level.maxTotalScrapValue; level.factorySizeMultiplier = config.FactorySizeMultiplier; level.minScrap = config.MinScrap; level.maxScrap = config.MaxScrap; if (minScrap > 0) { level.minTotalScrapValue = Mathf.RoundToInt((float)config.MinScrap * ((float)minTotalScrapValue / (float)minScrap)); } else { level.minTotalScrapValue = config.MinScrap * 45; } if (maxScrap > 0) { level.maxTotalScrapValue = Mathf.RoundToInt((float)config.MaxScrap * ((float)maxTotalScrapValue / (float)maxScrap)); } else { level.maxTotalScrapValue = config.MaxScrap * 75; } level.maxEnemyPowerCount = config.MaxIndoorPower; level.maxInsideDiversityPowerCount = config.MaxIndoorPower; level.maxDaytimeEnemyPowerCount = config.MaxIndoorPower; level.maxOutsideEnemyPowerCount = config.MaxOutdoorPower; level.maxOutsideDiversityPowerCount = config.MaxOutdoorPower; ApplyDungeonWeights(level, config.FacilityChance, config.MineshaftChance, config.MansionChance); } } private static void ApplyDungeonWeights(SelectableLevel level, int facilityChance, int mineshaftChance, int mansionChance) { if (!((Object)(object)level == (Object)null) && level.dungeonFlowTypes != null) { SetRarityAtIndex(level.dungeonFlowTypes, 0, facilityChance); SetRarityAtIndex(level.dungeonFlowTypes, 1, mineshaftChance); SetRarityAtIndex(level.dungeonFlowTypes, 2, mansionChance); } } private static void SetRarityAtIndex(Array dungeonFlowTypes, int index, int value) { if (dungeonFlowTypes == null || index < 0 || index >= dungeonFlowTypes.Length) { return; } object value2 = dungeonFlowTypes.GetValue(index); if (value2 != null) { FieldInfo field = value2.GetType().GetField("rarity", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { field.SetValue(value2, value); } } } private static void ApplyDineLootPool(SelectableLevel dineLevel) { if ((Object)(object)dineLevel == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.levels == null) { return; } SelectableLevel[] levels = StartOfRound.Instance.levels; foreach (SelectableLevel val in levels) { if (!((Object)(object)val != (Object)null) || !(NormalizeMoonName(val.PlanetName) == "Rend")) { continue; } FieldInfo field = typeof(SelectableLevel).GetField("spawnableScrap", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field2 = typeof(SelectableLevel).GetField("spawnableScrap", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field2 != null) { object value = field.GetValue(val); field2.SetValue(dineLevel, value); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)"Dine loot pool reset to a Rend-like scrap pool."); } } break; } } } }