Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BaconGameRules v1.2.0
BepInEx/plugins/BaconGameRules.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using DunGen.Graph; using HarmonyLib; using LethalLevelLoader; using Microsoft.CodeAnalysis; using TMPro; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [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("BaconGameRules")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("BaconGameRules")] [assembly: AssemblyTitle("BaconGameRules")] [assembly: AssemblyMetadata("AI_Assisted_Creation", "Code generated with Claude Code, Anthropic's AI coding agent")] [assembly: AssemblyMetadata("AI_Model_Vendor", "Anthropic")] [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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BaconGameRules { internal enum Difficulty { Easy, Normal, Hard, Brutal, Custom } internal sealed class PresetValues { internal int Credits = 60; internal int Quota = 130; internal int Growth = 100; internal int Days = 3; internal int DayLength; internal int ScrapAmount = 100; internal int ScrapValue = 100; internal int Enemies = 100; internal int SpawnRate = 100; internal int Mines = 100; internal int Turrets = 100; internal int Traps = 100; internal static PresetValues For(Difficulty preset) { return preset switch { Difficulty.Easy => new PresetValues { Credits = 150, Quota = 100, Growth = 75, Days = 4, DayLength = 20, Enemies = 75, SpawnRate = 75, Mines = 50, Turrets = 50, Traps = 50 }, Difficulty.Hard => new PresetValues { Credits = 30, Quota = 200, Growth = 150, Days = 3, DayLength = -10, Enemies = 125, SpawnRate = 125, Mines = 150, Turrets = 150, Traps = 150 }, Difficulty.Brutal => new PresetValues { Credits = 0, Quota = 250, Growth = 200, Days = 3, DayLength = -20, Enemies = 200, SpawnRate = 200, Mines = 200, Turrets = 200, Traps = 200 }, _ => new PresetValues(), }; } } internal sealed class SlotSetup { internal readonly int Slot; internal readonly ConfigEntry<Difficulty> Preset; internal readonly ConfigEntry<int> Credits; internal readonly ConfigEntry<int> Quota; internal readonly ConfigEntry<int> GrowthPercent; internal readonly ConfigEntry<int> DaysPerQuota; internal readonly ConfigEntry<int> DayLengthPercent; internal readonly ConfigEntry<int> ScrapAmountPercent; internal readonly ConfigEntry<int> ScrapValuePercent; internal readonly ConfigEntry<int> EnemyPercent; internal readonly ConfigEntry<int> SpawnRatePercent; internal readonly ConfigEntry<int> MinesPercent; internal readonly ConfigEntry<int> TurretsPercent; internal readonly ConfigEntry<int> TrapsPercent; internal readonly ConfigEntry<int> ScaledFor; internal int Crew => Mathf.Clamp(ScaledFor.Value, 1, 10); internal SlotSetup(ConfigFile file, int slot) { Slot = slot; string text = $"File {slot + 1}"; Preset = file.Bind<Difficulty>(text, "Difficulty", Difficulty.Normal, "Easy, Normal, Hard, Brutal or Custom. Normal leaves the game's values alone."); PresetValues presetValues = PresetValues.For(Preset.Value); Credits = file.Bind<int>(text, "Starting credits", presetValues.Credits, "Credits on a new save."); Quota = file.Bind<int>(text, "Starting quota", presetValues.Quota, "First quota on a new save."); GrowthPercent = file.Bind<int>(text, "Quota growth percent", presetValues.Growth, "How fast the quota grows. 100 is the game's speed."); DaysPerQuota = file.Bind<int>(text, "Days per quota", presetValues.Days, "Days the crew gets to reach each quota."); DayLengthPercent = file.Bind<int>(text, "Day length percent", presetValues.DayLength, "How much longer or shorter each day is. 0 is the game's length, 20 is 20% longer, -20 is 20% shorter."); ScrapAmountPercent = file.Bind<int>(text, "Scrap amount percent", presetValues.ScrapAmount, "How much scrap spawns, on top of weather bonuses. 100 is normal."); ScrapValuePercent = file.Bind<int>(text, "Scrap value percent", presetValues.ScrapValue, "What scrap sells for, on top of weather bonuses. 100 is normal."); EnemyPercent = file.Bind<int>(text, "Enemies percent", presetValues.Enemies, "How many enemies a moon can hold at once. 100 is normal."); SpawnRatePercent = file.Bind<int>(text, "Enemy spawn rate percent", presetValues.SpawnRate, "How many enemies come out each hour, so attacks start sooner. Enemies percent still caps how many a moon holds. 100 is normal."); MinesPercent = file.Bind<int>(text, "Mines percent", presetValues.Mines, "How many mines an interior gets. 0 is none, 100 is normal."); TurretsPercent = file.Bind<int>(text, "Turrets percent", presetValues.Turrets, "How many turrets an interior gets. 0 is none, 100 is normal."); TrapsPercent = file.Bind<int>(text, "Other traps percent", presetValues.Traps, "How many spike traps an interior gets, and traps from mods that the game counts as hazards. 0 is none, 100 is normal."); ScaledFor = file.Bind<int>(text, "Scaled for players", 4, "How many players this save is balanced for, 1 to 10, on top of the difficulty. Each player under 4 makes scrap worth 10% more and brings 10% fewer enemies and traps. Each player over 4 adds 10% more scrap and 5% more enemies and traps. 4 changes nothing."); } internal void Choose(Difficulty preset) { Preset.Value = preset; if (preset != Difficulty.Custom) { PresetValues presetValues = PresetValues.For(preset); Credits.Value = presetValues.Credits; Quota.Value = presetValues.Quota; GrowthPercent.Value = presetValues.Growth; DaysPerQuota.Value = presetValues.Days; DayLengthPercent.Value = presetValues.DayLength; ScrapAmountPercent.Value = presetValues.ScrapAmount; ScrapValuePercent.Value = presetValues.ScrapValue; EnemyPercent.Value = presetValues.Enemies; SpawnRatePercent.Value = presetValues.SpawnRate; MinesPercent.Value = presetValues.Mines; TurretsPercent.Value = presetValues.Turrets; TrapsPercent.Value = presetValues.Traps; } } } public static class GameSetup { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__ReceiveDaySpeed; } internal const int NormalCredits = 60; internal const int NormalQuota = 130; internal const int NormalDays = 3; internal const int NormalDaySeconds = 700; private const string DaySpeedMessage = "BaconFixer.DaySpeed"; private const float MinDaySpeed = 0.2f; private const float MaxDaySpeed = 4f; private const float SendInterval = 5f; internal const int BaseCrew = 4; internal const int MinCrew = 1; internal const int MaxCrew = 10; private const float CrewValueStep = 0.1f; private const float CrewAmountStep = 0.1f; private const float CrewFewerDanger = 0.1f; private const float CrewMoreDanger = 0.05f; private static readonly SlotSetup[] Slots = new SlotSetup[3]; private static bool _presetActive; private static bool _hosting; private static bool _dayLengthChanged; private static int _daysPerQuota; private static float _nextSend; private static readonly float[] SaveFactors = NewFactors(); private static readonly List<Func<SelectableLevel, float>>[] ExtraFactors = NewExtraFactors(); private static readonly string[] SpawnRateMethods = new string[4] { "PlotOutEnemiesForNextHour", "SpawnEnemiesOutside", "SpawnDaytimeEnemiesOutside", "PredictAllOutsideEnemies" }; private static SelectableLevel _spawnRateLevel; private static AnimationCurve _insideRate; private static AnimationCurve _outsideRate; private static AnimationCurve _daytimeRate; private static int _spawnRateDepth; private static readonly List<KeyValuePair<IndoorMapHazard, AnimationCurve>> TrapCurves = new List<KeyValuePair<IndoorMapHazard, AnimationCurve>>(); private static Dictionary<string, int> _spawnedBefore; private static Vector3 _trapFactors = Vector3.one; public static float ScrapAmountFactor => Factor(Rule.ScrapAmount, CurrentLevel()); public static float ScrapValueFactor => Factor(Rule.ScrapValue, CurrentLevel()); private static float[] NewFactors() { float[] array = new float[Enum.GetValues(typeof(Rule)).Length]; for (int i = 0; i < array.Length; i++) { array[i] = 1f; } return array; } private static List<Func<SelectableLevel, float>>[] NewExtraFactors() { List<Func<SelectableLevel, float>>[] array = new List<Func<SelectableLevel, float>>[Enum.GetValues(typeof(Rule)).Length]; for (int i = 0; i < array.Length; i++) { array[i] = new List<Func<SelectableLevel, float>>(); } return array; } internal static void AddFactor(Rule rule, Func<SelectableLevel, float> factor) { ExtraFactors[(int)rule].Add(factor); } internal static float CrewFactor(Rule rule, int crew) { int num = Mathf.Max(0, 4 - crew); int num2 = Mathf.Max(0, crew - 4); return rule switch { Rule.ScrapValue => 1f + 0.1f * (float)num, Rule.ScrapAmount => 1f + 0.1f * (float)num2, Rule.QuotaGrowth => 1f, _ => 1f - 0.1f * (float)num + 0.05f * (float)num2, }; } internal static SelectableLevel CurrentLevel() { if (!((Object)(object)StartOfRound.Instance != (Object)null)) { return null; } return StartOfRound.Instance.currentLevel; } internal static float Factor(Rule rule, SelectableLevel level) { if (!_hosting) { return 1f; } float num = SaveFactors[(int)rule]; List<Func<SelectableLevel, float>> list = ExtraFactors[(int)rule]; for (int num2 = list.Count - 1; num2 >= 0; num2--) { try { num *= Mathf.Max(0f, list[num2](level)); } catch (Exception ex) { Plugin.Log.LogWarning((object)$"GameSetup: a mod's {rule} factor failed and is now ignored: {ex.Message}"); list.RemoveAt(num2); } } return num; } internal static void Apply(Harmony h, ConfigFile config) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown CarryOverFromBaconFixer(config); for (int i = 0; i < Slots.Length; i++) { Slots[i] = new SlotSetup(config, i); } h.PatchAll(typeof(GameSetup)); HarmonyMethod val = new HarmonyMethod(typeof(GameSetup), "ScaleSpawnRate", (Type[])null) { priority = 0 }; HarmonyMethod val2 = new HarmonyMethod(typeof(GameSetup), "RestoreSpawnRate", (Type[])null); string[] spawnRateMethods = SpawnRateMethods; foreach (string text in spawnRateMethods) { MethodInfo methodInfo = AccessTools.Method(typeof(RoundManager), text, (Type[])null, (Type[])null); if (methodInfo != null) { h.Patch((MethodBase)methodInfo, val, (HarmonyMethod)null, (HarmonyMethod)null, val2, (HarmonyMethod)null); } else { Plugin.Log.LogWarning((object)("GameSetup: the game has no RoundManager." + text + ", so enemy spawn rate leaves it alone")); } } } private static void CarryOverFromBaconFixer(ConfigFile config) { string text = Path.Combine(Paths.ConfigPath, "baconfixer.gamesetup.cfg"); if (!File.Exists(config.ConfigFilePath) && File.Exists(text)) { File.Copy(text, config.ConfigFilePath); config.Reload(); } } internal static SlotSetup ForSlot(int slot) { if (slot < 0 || slot >= Slots.Length) { return null; } return Slots[slot]; } [HarmonyPostfix] [HarmonyPatch(typeof(TimeOfDay), "Awake")] private static void ApplyRules(TimeOfDay __instance) { _presetActive = (_hosting = (_dayLengthChanged = false)); for (int i = 0; i < SaveFactors.Length; i++) { SaveFactors[i] = 1f; } GameNetworkManager instance = GameNetworkManager.Instance; SlotSetup slotSetup = (((Object)(object)instance != (Object)null && instance.isHostingGame) ? ForSlot(instance.saveFileNum) : null); QuotaSettings quotaVariables = __instance.quotaVariables; bool preset; if (slotSetup != null && quotaVariables != null) { _hosting = true; preset = slotSetup.Preset.Value != Difficulty.Normal; if (preset) { quotaVariables.startingCredits = slotSetup.Credits.Value; quotaVariables.startingQuota = slotSetup.Quota.Value; quotaVariables.baseIncrease *= (float)slotSetup.GrowthPercent.Value / 100f; quotaVariables.deadlineDaysAmount = slotSetup.DaysPerQuota.Value; _daysPerQuota = slotSetup.DaysPerQuota.Value; _dayLengthChanged = slotSetup.DayLengthPercent.Value != 0; __instance.globalTimeSpeedMultiplier *= 100f / (float)(100 + slotSetup.DayLengthPercent.Value); _presetActive = true; } int crew = slotSetup.Crew; float num = CrewFactor(Rule.ScrapValue, crew); float num2 = CrewFactor(Rule.ScrapAmount, crew); float num3 = CrewFactor(Rule.Enemies, crew); SaveFactors[0] = Of(slotSetup.ScrapAmountPercent) * num2; SaveFactors[1] = Of(slotSetup.ScrapValuePercent) * num; SaveFactors[2] = Of(slotSetup.EnemyPercent) * num3; SaveFactors[3] = Of(slotSetup.SpawnRatePercent) * num3; SaveFactors[4] = Of(slotSetup.MinesPercent) * num3; SaveFactors[5] = Of(slotSetup.TurretsPercent) * num3; SaveFactors[6] = Of(slotSetup.TrapsPercent) * num3; string text = $"scaled for {crew} (scrap value {num * 100f:0}%, scrap amount {num2 * 100f:0}%, enemies and traps {num3 * 100f:0}%)"; if (preset) { Plugin.Log.LogInfo((object)$"GameSetup: {slotSetup.Preset.Value} on file {instance.saveFileNum + 1}, {text}: {quotaVariables.startingCredits} credits, {quotaVariables.startingQuota} quota, {slotSetup.GrowthPercent.Value}% growth, {quotaVariables.deadlineDaysAmount} days, day length {slotSetup.DayLengthPercent.Value:+0;-0;0}% (clock speed {__instance.globalTimeSpeedMultiplier:0.###}), scrap {slotSetup.ScrapAmountPercent.Value}% amount {slotSetup.ScrapValuePercent.Value}% value, enemies {slotSetup.EnemyPercent.Value}% at a {slotSetup.SpawnRatePercent.Value}% spawn rate, mines {slotSetup.MinesPercent.Value}%, turrets {slotSetup.TurretsPercent.Value}%, other traps {slotSetup.TrapsPercent.Value}%"); } else if (crew != 4) { Plugin.Log.LogInfo((object)$"GameSetup: Normal on file {instance.saveFileNum + 1}, {text}"); } } float Of(ConfigEntry<int> percent) { if (!preset) { return 1f; } return (float)percent.Value / 100f; } } [HarmonyPrefix] [HarmonyPriority(0)] [HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")] private static void ApplyScrapRules(RoundManager __instance, out Vector2 __state) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) __state = new Vector2(__instance.scrapAmountMultiplier, __instance.scrapValueMultiplier); float num = Factor(Rule.ScrapAmount, __instance.currentLevel); float num2 = Factor(Rule.ScrapValue, __instance.currentLevel); __instance.scrapAmountMultiplier *= num; __instance.scrapValueMultiplier *= num2; if (_hosting && (!Mathf.Approximately(num, 1f) || !Mathf.Approximately(num2, 1f))) { Plugin.Log.LogInfo((object)$"GameSetup: scrap on {__instance.currentLevel?.PlanetName} at {num * 100f:0}% amount and {num2 * 100f:0}% value"); } } [HarmonyPostfix] [HarmonyPriority(800)] [HarmonyPatch(typeof(RoundManager), "SpawnScrapInLevel")] private static void RestoreScrapRules(RoundManager __instance, Vector2 __state) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) __instance.scrapAmountMultiplier = __state.x; __instance.scrapValueMultiplier = __state.y; } [HarmonyPostfix] [HarmonyPriority(0)] [HarmonyPatch(typeof(RoundManager), "RefreshEnemiesList")] private static void ApplyEnemyRules(RoundManager __instance) { if (_hosting && ((NetworkBehaviour)__instance).IsServer) { float num = Factor(Rule.Enemies, __instance.currentLevel); if (!Mathf.Approximately(num, 1f)) { __instance.currentMaxInsidePower *= num; __instance.currentMaxOutsidePower *= num; } } } private static void ScaleSpawnRate(RoundManager __instance, MethodBase __originalMethod) { if (_spawnRateDepth++ > 0 || !_hosting) { return; } SelectableLevel currentLevel = __instance.currentLevel; if ((Object)(object)currentLevel == (Object)null) { return; } float num = Factor(Rule.SpawnRate, currentLevel); if (!Mathf.Approximately(num, 1f)) { _spawnRateLevel = currentLevel; _insideRate = currentLevel.enemySpawnChanceThroughoutDay; _outsideRate = currentLevel.outsideEnemySpawnChanceThroughDay; _daytimeRate = currentLevel.daytimeEnemySpawnChanceThroughDay; currentLevel.enemySpawnChanceThroughoutDay = Scaled(_insideRate, num); currentLevel.outsideEnemySpawnChanceThroughDay = Scaled(_outsideRate, num); currentLevel.daytimeEnemySpawnChanceThroughDay = Scaled(_daytimeRate, num); if (__originalMethod.Name == "PredictAllOutsideEnemies") { Plugin.Log.LogInfo((object)$"GameSetup: enemies on {currentLevel.PlanetName} come out at a {num * 100f:0}% rate, up to {Factor(Rule.Enemies, currentLevel) * 100f:0}% of the moon's limit"); } } } private static void RestoreSpawnRate() { if (--_spawnRateDepth <= 0 && !((Object)(object)_spawnRateLevel == (Object)null)) { _spawnRateLevel.enemySpawnChanceThroughoutDay = _insideRate; _spawnRateLevel.outsideEnemySpawnChanceThroughDay = _outsideRate; _spawnRateLevel.daytimeEnemySpawnChanceThroughDay = _daytimeRate; _spawnRateLevel = null; } } [HarmonyPrefix] [HarmonyPriority(0)] [HarmonyPatch(typeof(RoundManager), "SpawnMapObjects")] private static void ScaleTraps(RoundManager __instance) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) TrapCurves.Clear(); SelectableLevel currentLevel = __instance.currentLevel; IndoorMapHazard[] array = (((Object)(object)currentLevel != (Object)null) ? currentLevel.indoorMapHazards : null); if (!_hosting || array == null) { return; } _trapFactors = new Vector3(Factor(Rule.Mines, currentLevel), Factor(Rule.Turrets, currentLevel), Factor(Rule.Traps, currentLevel)); IndoorMapHazard[] array2 = array; foreach (IndoorMapHazard val in array2) { GameObject val2 = (((Object)(object)val?.hazardType != (Object)null) ? val.hazardType.prefabToSpawn : null); if (!((Object)(object)val2 == (Object)null) && val.numberToSpawn != null) { float num = (((Object)(object)val2.GetComponentInChildren<Landmine>(true) != (Object)null) ? _trapFactors.x : (((Object)(object)val2.GetComponentInChildren<Turret>(true) != (Object)null) ? _trapFactors.y : ((val2.GetComponentInChildren<IIndoorMapHazard>(true) != null) ? _trapFactors.z : 1f))); if (!Mathf.Approximately(num, 1f)) { TrapCurves.Add(new KeyValuePair<IndoorMapHazard, AnimationCurve>(val, val.numberToSpawn)); val.numberToSpawn = Scaled(val.numberToSpawn, num); } } } if (TrapCurves.Count > 0) { _spawnedBefore = SpawnedByName(); } } [HarmonyFinalizer] [HarmonyPatch(typeof(RoundManager), "SpawnMapObjects")] private static void RestoreTraps(RoundManager __instance) { if (TrapCurves.Count == 0) { return; } Dictionary<string, int> dictionary = SpawnedByName(); List<string> list = new List<string>(); foreach (KeyValuePair<IndoorMapHazard, AnimationCurve> trapCurf in TrapCurves) { trapCurf.Key.numberToSpawn = trapCurf.Value; string name = ((Object)trapCurf.Key.hazardType.prefabToSpawn).name; dictionary.TryGetValue(name + "(Clone)", out var value); _spawnedBefore.TryGetValue(name + "(Clone)", out var value2); list.Add($"{value - value2} {name}"); } TrapCurves.Clear(); Plugin.Log.LogInfo((object)string.Format("GameSetup: traps on {0} at {1:0}% mines, {2:0}% turrets, {3:0}% other traps: {4}", __instance.currentLevel.PlanetName, _trapFactors.x * 100f, _trapFactors.y * 100f, _trapFactors.z * 100f, string.Join(", ", list))); } private static Dictionary<string, int> SpawnedByName() { Dictionary<string, int> dictionary = new Dictionary<string, int>(); NetworkObject[] array = Object.FindObjectsOfType<NetworkObject>(); foreach (NetworkObject val in array) { dictionary.TryGetValue(((Object)val).name, out var value); dictionary[((Object)val).name] = value + 1; } return dictionary; } private static AnimationCurve Scaled(AnimationCurve curve, float factor) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown if (curve == null) { return null; } Keyframe[] keys = curve.keys; for (int i = 0; i < keys.Length; i++) { ref Keyframe reference = ref keys[i]; ((Keyframe)(ref reference)).value = ((Keyframe)(ref reference)).value * factor; ref Keyframe reference2 = ref keys[i]; ((Keyframe)(ref reference2)).inTangent = ((Keyframe)(ref reference2)).inTangent * factor; ref Keyframe reference3 = ref keys[i]; ((Keyframe)(ref reference3)).outTangent = ((Keyframe)(ref reference3)).outTangent * factor; } return new AnimationCurve(keys) { preWrapMode = curve.preWrapMode, postWrapMode = curve.postWrapMode }; } [HarmonyPostfix] [HarmonyPatch(typeof(TimeOfDay), "Start")] private static void ListenForDaySpeed() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if (singleton == null) { return; } CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager; if (customMessagingManager != null) { object obj = <>O.<0>__ReceiveDaySpeed; if (obj == null) { HandleNamedMessageDelegate val = ReceiveDaySpeed; <>O.<0>__ReceiveDaySpeed = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("BaconFixer.DaySpeed", (HandleNamedMessageDelegate)obj); } } [HarmonyPostfix] [HarmonyPatch(typeof(TimeOfDay), "SyncTimeClientRpc")] private unsafe static void SendDaySpeed(TimeOfDay __instance) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) if (!_dayLengthChanged || !((NetworkBehaviour)__instance).IsServer || Time.unscaledTime < _nextSend) { return; } _nextSend = Time.unscaledTime + 5f; float globalTimeSpeedMultiplier = __instance.globalTimeSpeedMultiplier; FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<float>(ref globalTimeSpeedMultiplier, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("BaconFixer.DaySpeed", val, (NetworkDelivery)2); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void ReceiveDaySpeed(ulong sender, FastBufferReader message) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) float num = default(float); ((FastBufferReader)(ref message)).ReadValueSafe<float>(ref num, default(ForPrimitives)); TimeOfDay instance = TimeOfDay.Instance; if ((Object)(object)instance != (Object)null && !((NetworkBehaviour)instance).IsServer) { instance.globalTimeSpeedMultiplier = Mathf.Clamp(num, 0.2f, 4f); } } [HarmonyPrefix] [HarmonyPatch(typeof(TimeOfDay), "SetNewProfitQuota")] private static void ScaleQuotaGrowth(TimeOfDay __instance, out float __state) { __state = float.NaN; QuotaSettings quotaVariables = __instance.quotaVariables; if (((NetworkBehaviour)__instance).IsServer && quotaVariables != null) { float num = Factor(Rule.QuotaGrowth, null); if (!Mathf.Approximately(num, 1f)) { __state = quotaVariables.baseIncrease; quotaVariables.baseIncrease *= num; Plugin.Log.LogInfo((object)$"GameSetup: the quota grows at {num * 100f:0}% this time"); } } } [HarmonyFinalizer] [HarmonyPatch(typeof(TimeOfDay), "SetNewProfitQuota")] private static void RestoreQuotaGrowth(TimeOfDay __instance, float __state) { if (!float.IsNaN(__state) && __instance.quotaVariables != null) { __instance.quotaVariables.baseIncrease = __state; } } [HarmonyPostfix] [HarmonyPatch(typeof(TimeOfDay), "SetNewProfitQuota")] private static void SyncDeadline(TimeOfDay __instance) { if (_presetActive && ((NetworkBehaviour)__instance).IsServer) { __instance.SyncTimeClientRpc(__instance.globalTime, (int)(__instance.totalTime * (float)_daysPerQuota)); } } [HarmonyPostfix] [HarmonyPatch(typeof(TimeOfDay), "SetBuyingRateForDay")] private static void SyncBuyingRate(TimeOfDay __instance) { StartOfRound instance = StartOfRound.Instance; if (_presetActive && (Object)(object)instance != (Object)null && ((NetworkBehaviour)__instance).IsServer && ((NetworkBehaviour)instance).IsSpawned) { instance.SyncCompanyBuyingRateClientRpc(instance.companyBuyingRate); } } [HarmonyPostfix] [HarmonyPatch(typeof(MenuManager), "Start")] private static void BuildPanel(MenuManager __instance) { GameSetupPanel.Build(__instance); } [HarmonyPostfix] [HarmonyPatch(typeof(MenuManager), "ClickHostButton")] private static void RefreshOnHostScreen() { GameSetupPanel.Close(); } [HarmonyPostfix] [HarmonyPatch(typeof(SaveFileUISlot), "SetFileToThis")] private static void OpenOnFileChosen() { GameSetupPanel.Open(); } } internal static class GameSetupPanel { private const float WindowWidth = 880f; private const float ColumnGap = 18f; private const float RulesWidth = 286f; private const float ButtonHeight = 17f; private const float StepperWidth = 18f; private const float ValueWidth = 92f; private const float PresetWidth = 64f; private const float ScreenMargin = 0.95f; private const float TitleSize = 15f; private const float HeadingSize = 11.5f; private const float TextSize = 10.5f; private const float SmallSize = 9f; private const float ValueSize = 15f; private static readonly Color Orange = new Color(1f, 0.42f, 0.13f); private static readonly Color Dim = new Color(1f, 0.55f, 0.32f, 0.85f); private static readonly Color Fill = new Color(0.085f, 0.012f, 0.01f, 0.98f); private static readonly Color Border = new Color(0.72f, 0.05f, 0.04f); private static readonly Color Shade = new Color(0f, 0f, 0f, 0.6f); private static readonly Color ButtonOff = new Color(1f, 0.42f, 0.13f, 0.14f); private static readonly Color ButtonHover = new Color(1f, 0.42f, 0.13f, 0.38f); private static readonly Color TypedSelection = new Color(1f, 0.85f, 0.6f, 0.45f); private static readonly Color RowHover = new Color(1f, 0.42f, 0.13f, 0.08f); private static GameObject _window; private static GameObject _bar; private static RectTransform _frame; private static TMP_FontAsset _font; private static TextMeshProUGUI _title; private static TextMeshProUGUI _summary; private static TextMeshProUGUI _note; private static TextMeshProUGUI _moons; private static TextMeshProUGUI _ruleTitle; private static TextMeshProUGUI _ruleValue; private static TextMeshProUGUI _ruleText; private static TextMeshProUGUI _ruleDetails; private static GameObject _infoRule; private static GameObject _infoGeneral; private static Action<SlotSetup> _showRule; private static readonly Dictionary<Difficulty, Button> PresetButtons = new Dictionary<Difficulty, Button>(); private static readonly List<Action<SlotSetup>> RowUpdates = new List<Action<SlotSetup>>(); private const string LockedText = "Locked: this save has started, and it keeps what it began with until the crew gets fired. A new save can pick it."; private static SlotSetup Current => GameSetup.ForSlot(((Object)(object)GameNetworkManager.Instance != (Object)null) ? GameNetworkManager.Instance.saveFileNum : (-1)); private static bool Started { get { if ((Object)(object)GameNetworkManager.Instance != (Object)null) { return File.Exists(Path.Combine(Application.persistentDataPath, GameNetworkManager.Instance.currentSaveFileName)); } return false; } } internal static void Build(MenuManager menu) { if (!((Object)(object)menu.HostSettingsScreen == (Object)null) && !((Object)(object)menu.lobbyNameInputField == (Object)null)) { PresetButtons.Clear(); RowUpdates.Clear(); _font = menu.lobbyNameInputField.textComponent.font; BuildBar(menu.HostSettingsScreen.transform); BuildWindow(menu.HostSettingsScreen.transform); Close(); } } internal static void Open() { if ((Object)(object)_window == (Object)null || Current == null) { Close(); return; } _window.SetActive(true); _window.transform.SetAsLastSibling(); Refresh(); FitOnScreen(); } private static void FitOnScreen() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) Canvas componentInParent = ((Component)_frame).GetComponentInParent<Canvas>(); if (!((Object)(object)componentInParent == (Object)null)) { RectTransform val = (RectTransform)((Component)componentInParent.rootCanvas).transform; ((Transform)_frame).localScale = Vector3.one; LayoutRebuilder.ForceRebuildLayoutImmediate(_frame); Rect rect = _frame.rect; Vector2 val2 = ((Rect)(ref rect)).size * (((Transform)_frame).lossyScale.x / ((Transform)val).lossyScale.x); rect = val.rect; Vector2 val3 = ((Rect)(ref rect)).size * 0.95f; if (!(val2.x <= 0f) && !(val2.y <= 0f)) { float num = Mathf.Min(new float[3] { 1f, val3.x / val2.x, val3.y / val2.y }); ((Transform)_frame).localScale = new Vector3(num, num, 1f); } } } internal static void Close() { if ((Object)(object)_window != (Object)null) { _window.SetActive(false); } Refresh(); } private static void Refresh() { if ((Object)(object)_bar == (Object)null) { return; } SlotSetup current = Current; _bar.SetActive(current != null); if (current == null) { return; } int num = GameNetworkManager.Instance.saveFileNum + 1; ((TMP_Text)_summary).text = $"FILE {num} RULES: {current.Preset.Value.ToString().ToUpperInvariant()}, SCALED FOR {current.Crew} ${current.Credits.Value} Quota ${current.Quota.Value} {current.DaysPerQuota.Value} days Day {DayLengthText(current.DayLengthPercent.Value)}"; ((TMP_Text)_title).text = $"GAME RULES: FILE {num}"; foreach (KeyValuePair<Difficulty, Button> presetButton in PresetButtons) { Paint(presetButton.Value, presetButton.Key == current.Preset.Value); } foreach (Action<SlotSetup> rowUpdate in RowUpdates) { rowUpdate(current); } ((TMP_Text)_moons).text = (LevelLoaderDetails.Installed ? LevelLoaderDetails.MoonClocks(current.DayLengthPercent.Value) : "Needs LethalLevelLoader to list them."); bool started = Started; ((TMP_Text)_note).text = (started ? "THIS SAVE HAS STARTED. Crew size, day length, scrap, enemies and traps apply right away, and quota growth and days from its next quota. Starting credits and quota only apply if the crew gets fired." : "NEW SAVE. All of these apply when you host it. You can change them again each time you host."); ShowInfo(); } private static void ShowInfo() { if (!((Object)(object)_infoRule == (Object)null)) { SlotSetup current = Current; bool flag = _showRule != null && current != null; _infoRule.SetActive(flag); _infoGeneral.SetActive(!flag); if (flag) { _showRule(current); } } } private static void BuildBar(Transform parent) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) _bar = NewObject("BaconGameRules Rules Bar", parent); RectTransform val = (RectTransform)_bar.transform; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(1f, 0f); val.pivot = val2; Vector2 anchorMin = (val.anchorMax = val2); val.anchorMin = anchorMin; val.anchoredPosition = new Vector2(-36f, 6f); MakeFrame(_bar); HorizontalLayoutGroup obj = _bar.AddComponent<HorizontalLayoutGroup>(); ((LayoutGroup)obj).padding = new RectOffset(8, 6, 4, 4); ((HorizontalOrVerticalLayoutGroup)obj).spacing = 10f; ((LayoutGroup)obj).childAlignment = (TextAnchor)3; bool childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true); ((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = childControlWidth; childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false); ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = childControlWidth; ContentSizeFitter obj2 = _bar.AddComponent<ContentSizeFitter>(); FitMode horizontalFit = (FitMode)2; obj2.verticalFit = (FitMode)2; obj2.horizontalFit = horizontalFit; _summary = NewText(_bar.transform, "", 9.5f, Orange); NewButton(_bar.transform, "EDIT RULES", 66f, Open); } private static void BuildWindow(Transform parent) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_04a7: Unknown result type (might be due to invalid IL or missing references) //IL_052f: Unknown result type (might be due to invalid IL or missing references) //IL_08db: Unknown result type (might be due to invalid IL or missing references) //IL_08fe: Unknown result type (might be due to invalid IL or missing references) //IL_092b: Unknown result type (might be due to invalid IL or missing references) //IL_098f: Unknown result type (might be due to invalid IL or missing references) //IL_09a4: Unknown result type (might be due to invalid IL or missing references) //IL_09d6: Unknown result type (might be due to invalid IL or missing references) //IL_09fc: Unknown result type (might be due to invalid IL or missing references) //IL_0a1e: Unknown result type (might be due to invalid IL or missing references) _window = NewObject("BaconGameRules Window", parent); RectTransform val = (RectTransform)_window.transform; val.anchorMin = Vector2.zero; val.anchorMax = Vector2.one; val.offsetMin = new Vector2(-100f, -100f); val.offsetMax = new Vector2(100f, 100f); ((Graphic)_window.AddComponent<Image>()).color = Shade; GameObject val2 = NewObject("Window", _window.transform); RectTransform val3 = (RectTransform)val2.transform; _frame = val3; Vector2 val4 = default(Vector2); ((Vector2)(ref val4))..ctor(0.5f, 0.5f); val3.pivot = val4; Vector2 anchorMin = (val3.anchorMax = val4); val3.anchorMin = anchorMin; val3.sizeDelta = new Vector2(880f, 0f); MakeFrame(val2); VerticalLayoutGroup val6 = NewVertical(val2, 7f); ((LayoutGroup)val6).padding = new RectOffset(14, 14, 10, 10); val2.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2; Transform parent2 = NewRow(val2.transform, 4f); _title = NewText(parent2, "GAME RULES", 15f, Orange); ((Component)_title).gameObject.AddComponent<LayoutElement>().flexibleWidth = 1f; foreach (Difficulty value in Enum.GetValues(typeof(Difficulty))) { Difficulty choice = value; PresetButtons[value] = NewButton(parent2, value.ToString().ToUpperInvariant(), 64f, delegate { Current?.Choose(choice); Refresh(); }); } Transform obj = NewRow(val2.transform, 18f); ((LayoutGroup)((Component)obj).GetComponent<HorizontalLayoutGroup>()).childAlignment = (TextAnchor)0; float width = 880f - (float)((LayoutGroup)val6).padding.horizontal - 36f - 572f; Transform val7 = NewColumn(obj, 286f, 4f); Transform val8 = NewColumn(obj, 286f, 4f); Transform parent3 = NewColumn(obj, width, 5f); NewText(val7, "QUOTA AND TIME", 11.5f, Orange); AddRule(val7, "Starting credits", "Credits a new save starts with.", (SlotSetup setup) => setup.Credits, 20, 0, 100000, (int value) => $"${value}", makesCustom: true, NewSaveOnly); AddRule(val7, "Starting quota", "The first quota on a new save.", (SlotSetup setup) => setup.Quota, 20, 20, 100000, (int value) => $"${value}", makesCustom: true, NewSaveOnly); AddRule(val7, "Quota growth", "How fast the quota rises after each deadline. 100% is the game's own growth.", (SlotSetup setup) => setup.GrowthPercent, 5, 25, 500, Percent, makesCustom: true, FromNextQuota); AddRule(val7, "Days per quota", "Days you get to reach each quota before the deadline. The game's own is 3.", (SlotSetup setup) => setup.DaysPerQuota, 1, 1, 10, (int value) => value.ToString(), makesCustom: true, FromNextQuota); AddRule(val7, "Day length", "How long each day lasts in real time.", (SlotSetup setup) => setup.DayLengthPercent, 10, -50, 200, DayLengthText, makesCustom: true, DayLengthDetails); NewText(val8, "CREW SIZE", 11.5f, Orange); AddRule(val8, "Scaled for", "Players this save is balanced for. Under 4: scrap is worth more, and there are fewer enemies and traps. Over 4: more scrap, and more enemies and traps.", (SlotSetup setup) => setup.ScaledFor, 1, 1, 10, Players, makesCustom: false, (SlotSetup setup) => CrewText(setup.Crew)); NewText(val8, "ON THE MOON", 11.5f, Orange); AddRule(val8, "Scrap amount", "How much scrap spawns, on top of weather bonuses.", (SlotSetup setup) => setup.ScrapAmountPercent, 10, 10, 500, Percent, makesCustom: true, Effective(Rule.ScrapAmount, (SlotSetup setup) => setup.ScrapAmountPercent)); AddRule(val8, "Scrap value", "What scrap sells for, on top of weather bonuses.", (SlotSetup setup) => setup.ScrapValuePercent, 10, 10, 500, Percent, makesCustom: true, Effective(Rule.ScrapValue, (SlotSetup setup) => setup.ScrapValuePercent)); AddRule(val8, "Enemies", "How many enemies a moon can hold at once.", (SlotSetup setup) => setup.EnemyPercent, 25, 25, 400, Percent, makesCustom: true, Effective(Rule.Enemies, (SlotSetup setup) => setup.EnemyPercent)); AddRule(val8, "Enemy spawn rate", "How many come out each hour, so attacks start sooner.", (SlotSetup setup) => setup.SpawnRatePercent, 25, 25, 400, Percent, makesCustom: true, Effective(Rule.SpawnRate, (SlotSetup setup) => setup.SpawnRatePercent)); AddRule(val8, "Mines", "How many mines each interior gets.", (SlotSetup setup) => setup.MinesPercent, 25, 0, 500, Percent, makesCustom: true, Effective(Rule.Mines, (SlotSetup setup) => setup.MinesPercent)); AddRule(val8, "Turrets", "How many turrets each interior gets.", (SlotSetup setup) => setup.TurretsPercent, 25, 0, 500, Percent, makesCustom: true, Effective(Rule.Turrets, (SlotSetup setup) => setup.TurretsPercent)); AddRule(val8, "Other traps", "Spike traps, and traps from other mods.", (SlotSetup setup) => setup.TrapsPercent, 25, 0, 500, Percent, makesCustom: true, Effective(Rule.Traps, (SlotSetup setup) => setup.TrapsPercent)); AddOtherModsRules(val7, 5, val8, 8); _infoRule = NewObject("Rule info", parent3); NewVertical(_infoRule, 6f); _ruleTitle = NewText(_infoRule.transform, "", 12.5f, Orange); _ruleValue = NewText(_infoRule.transform, "", 15f, Orange); _ruleText = NewWrappedText(_infoRule.transform, ""); ((Graphic)_ruleText).color = Orange; _ruleDetails = NewWrappedText(_infoRule.transform, ""); _infoRule.SetActive(false); _infoGeneral = NewObject("General info", parent3); NewVertical(_infoGeneral, 5f); Transform transform = _infoGeneral.transform; ((Graphic)NewWrappedText(transform, "Point at a rule to see what it does.")).color = Orange; NewText(transform, "HOW TIME WORKS", 11.5f, Orange); NewWrappedText(transform, "A normal day is " + Minutes(0) + " minutes from landing to midnight at +0%. Day length makes the clock run slower or faster, and the ship still leaves at the same clock time."); NewText(transform, "MOONS WITH THEIR OWN CLOCK", 11.5f, Orange); _moons = NewWrappedText(transform, ""); NewText(transform, "SEEDS", 11.5f, Orange); NewWrappedText(transform, "Every landing's map seed is saved. In the terminal, SEED shows it and the last ones, and the host can type SEED and a number to land on that seed next time."); NewText(transform, "THIS SAVE", 11.5f, Orange); _note = NewWrappedText(transform, ""); Transform val9 = NewRow(val2.transform, 4f); ((LayoutGroup)((Component)val9).GetComponent<HorizontalLayoutGroup>()).childAlignment = (TextAnchor)5; NewObject("Space", val9).AddComponent<LayoutElement>().flexibleWidth = 1f; NewButton(val9, "DONE", 80f, Close); } private static string Percent(int value) { return $"{value}%"; } private static string NewSaveOnly(SlotSetup setup) { return "Used when a new save starts, and again when the crew gets fired."; } private static string FromNextQuota(SlotSetup setup) { return "On a save that has started, it counts from the next quota."; } private static string DayLengthDetails(SlotSetup setup) { return "This file: " + Minutes(setup.DayLengthPercent.Value) + " minutes from landing to midnight. The game's own day is " + Minutes(0) + " minutes.\n\nThe clock runs slower or faster, and the ship still leaves at the same clock time. Scrap doesn't change, and enemies still arrive by clock time, so a longer day is more time to loot, not more enemies."; } private static string CrewText(int crew) { if (crew == 4) { return $"Scaled for {crew}: the game's own balance, so nothing changes."; } return $"Scaled for {crew}:\nScrap value {Signed(GameSetup.CrewFactor(Rule.ScrapValue, crew))}\nScrap amount {Signed(GameSetup.CrewFactor(Rule.ScrapAmount, crew))}\n" + "Enemies and traps " + Signed(GameSetup.CrewFactor(Rule.Enemies, crew)) + "\n\nThe quota, the days and the length of a day never change with crew size."; } private static Func<SlotSetup, string> Effective(Rule rule, Func<SlotSetup, ConfigEntry<int>> entry) { return delegate(SlotSetup setup) { float num = GameSetup.CrewFactor(rule, setup.Crew); return Mathf.Approximately(num, 1f) ? $"Scaled for {setup.Crew}: crew size leaves it as it is." : $"Scaled for {setup.Crew}, it comes to {Mathf.RoundToInt((float)entry(setup).Value * num)}% in the end."; }; } private static string Signed(float factor) { int num = Mathf.RoundToInt((factor - 1f) * 100f); if (num != 0) { return $"{num:+0;-0}%"; } return "unchanged"; } private static string Players(int value) { if (value != 1) { return $"{value} players"; } return "1 player"; } private static void AddOtherModsRules(Transform left, int leftRows, Transform right, int rightRows) { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); foreach (RulesApi.ExtraRule extraRule in RulesApi.ExtraRules) { if (!list.Contains(extraRule.Heading)) { list.Add(extraRule.Heading); } } foreach (string heading in list) { List<RulesApi.ExtraRule> list2 = RulesApi.ExtraRules.FindAll((RulesApi.ExtraRule rule) => rule.Heading == heading); bool num = leftRows <= rightRows; Transform val = (num ? left : right); if (num) { leftRows += list2.Count + 1; } else { rightRows += list2.Count + 1; } if (heading.Length > 0) { NewText(val, heading, 11.5f, Orange); } foreach (RulesApi.ExtraRule item in list2) { AddExtraRule(val, item); } } } private static void AddExtraRule(Transform column, RulesApi.ExtraRule rule) { Func<int, ConfigEntry<int>> entry = rule.Entry; string[] options = rule.Options; Func<SlotSetup, string> func = ((options != null) ? ((Func<SlotSetup, string>)((SlotSetup _) => "Options: " + string.Join(", ", options) + ".")) : null); if (rule.LockedOnceStarted) { Func<SlotSetup, string> plain = func; func = delegate(SlotSetup setup) { object obj; if (!Started) { obj = plain?.Invoke(setup); if (obj == null) { return ""; } } else { obj = "Locked: this save has started, and it keeps what it began with until the crew gets fired. A new save can pick it."; } return (string)obj; }; } AddRule(column, rule.Label, rule.Description, (SlotSetup setup) => entry(setup.Slot), rule.Step, rule.Min, rule.Max, rule.Format, makesCustom: false, func, options, rule.LockedOnceStarted); } private static string DayLengthText(int percent) { return $"{percent:+0;-0;+0}% ({Minutes(percent)} min)"; } private static string Minutes(int percent) { return ((float)(700 * (100 + percent)) / 100f / 60f).ToString("0.#", CultureInfo.InvariantCulture); } private static void AddRule(Transform parent, string label, string description, Func<SlotSetup, ConfigEntry<int>> entry, int step, int min, int max, Func<int, string> format, bool makesCustom = true, Func<SlotSetup, string> details = null, string[] options = null, bool locked = false) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) GameObject val = NewObject("Rule", parent); NewVertical(val, 0f); Image hover = val.AddComponent<Image>(); ((Graphic)hover).color = Color.clear; EventTrigger trigger = val.AddComponent<EventTrigger>(); AddTrigger(trigger, (EventTriggerType)0, delegate { //IL_0006: Unknown result type (might be due to invalid IL or missing references) ((Graphic)hover).color = RowHover; _showRule = Show; ShowInfo(); }); AddTrigger(trigger, (EventTriggerType)1, delegate { //IL_0006: Unknown result type (might be due to invalid IL or missing references) ((Graphic)hover).color = Color.clear; _showRule = null; ShowInfo(); }); Transform parent2 = NewRow(val.transform, 3f); ((Component)NewText(parent2, label, 10.5f, Orange)).gameObject.AddComponent<LayoutElement>().flexibleWidth = 1f; int count; if (options != null) { count = max - min + 1; NewButton(parent2, "<", 18f, delegate { if (Current != null) { Set(Turn(entry(Current).Value, -1)); } Refresh(); }); TextMeshProUGUI shown = NewValueBox(parent2); NewButton(parent2, ">", 18f, delegate { if (Current != null) { Set(Turn(entry(Current).Value, 1)); } Refresh(); }); RowUpdates.Add(delegate(SlotSetup setup) { ((TMP_Text)shown).text = ((locked && Started) ? "LOCKED " : "") + format(Mathf.Clamp(entry(setup).Value, min, max)); }); return; } NewButton(parent2, "-", 18f, delegate { if (Current != null) { Set(entry(Current).Value - step); } Refresh(); }); TMP_InputField field = NewNumberField(parent2); NewButton(parent2, "+", 18f, delegate { if (Current != null) { Set(entry(Current).Value + step); } Refresh(); }); RowUpdates.Add(delegate(SlotSetup setup) { field.text = format(Mathf.Clamp(entry(setup).Value, min, max)); }); ((UnityEvent<string>)(object)field.onSelect).AddListener((UnityAction<string>)delegate { if (Current != null) { field.text = entry(Current).Value.ToString(CultureInfo.InvariantCulture); } }); ((UnityEvent<string>)(object)field.onEndEdit).AddListener((UnityAction<string>)delegate(string typed) { Match match = Regex.Match(typed ?? "", "-?\\d+"); if (match.Success && int.TryParse(match.Value, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out var result)) { Set(result); } else if (match.Success) { Set(match.Value.StartsWith("-") ? min : max); } Refresh(); }); void Set(int value) { SlotSetup current = Current; if (current != null && (!locked || !Started)) { value = Mathf.Clamp(value, min, max); if (entry(current).Value != value) { entry(current).Value = value; if (makesCustom) { current.Preset.Value = Difficulty.Custom; } } } } void Show(SlotSetup setup) { ((TMP_Text)_ruleTitle).text = label.ToUpperInvariant(); ((TMP_Text)_ruleValue).text = format(Mathf.Clamp(entry(setup).Value, min, max)); ((TMP_Text)_ruleText).text = description; ((TMP_Text)_ruleDetails).text = ((details != null) ? details(setup) : ""); } int Turn(int value, int by) { return min + ((value - min + by) % count + count) % count; } } private static void AddTrigger(EventTrigger trigger, EventTriggerType type, Action action) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown Entry val = new Entry { eventID = type }; ((UnityEvent<BaseEventData>)(object)val.callback).AddListener((UnityAction<BaseEventData>)delegate { action(); }); trigger.triggers.Add(val); } private static TextMeshProUGUI NewValueBox(Transform parent) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown GameObject obj = NewObject("Value", parent); LayoutElement obj2 = obj.AddComponent<LayoutElement>(); float preferredWidth = (obj2.minWidth = 92f); obj2.preferredWidth = preferredWidth; preferredWidth = (obj2.minHeight = 17f); obj2.preferredHeight = preferredWidth; ((Graphic)obj.AddComponent<Image>()).color = ButtonOff; TextMeshProUGUI obj3 = NewText(obj.transform, "", 10.5f, Orange); ((TMP_Text)obj3).alignment = (TextAlignmentOptions)514; ((TMP_Text)obj3).enableAutoSizing = true; ((TMP_Text)obj3).fontSizeMin = 7.35f; ((TMP_Text)obj3).fontSizeMax = 10.5f; Stretch((RectTransform)((TMP_Text)obj3).transform, 2f); return obj3; } private static TMP_InputField NewNumberField(Transform parent) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) GameObject val = NewObject("Value", parent); val.SetActive(false); LayoutElement obj = val.AddComponent<LayoutElement>(); float preferredWidth = (obj.minWidth = 92f); obj.preferredWidth = preferredWidth; preferredWidth = (obj.minHeight = 17f); obj.preferredHeight = preferredWidth; Image targetGraphic = val.AddComponent<Image>(); GameObject val2 = NewObject("Text Area", val.transform); val2.AddComponent<RectMask2D>(); Stretch((RectTransform)val2.transform, 2f); TextMeshProUGUI val3 = NewText(val2.transform, "", 10.5f, Orange); ((TMP_Text)val3).alignment = (TextAlignmentOptions)514; Stretch((RectTransform)((TMP_Text)val3).transform, 0f); TMP_InputField obj2 = val.AddComponent<TMP_InputField>(); obj2.textViewport = (RectTransform)val2.transform; obj2.textComponent = (TMP_Text)(object)val3; obj2.fontAsset = _font; obj2.pointSize = 10.5f; obj2.richText = false; obj2.lineType = (LineType)0; obj2.customCaretColor = true; obj2.caretColor = Orange; obj2.selectionColor = TypedSelection; ((Selectable)obj2).targetGraphic = (Graphic)(object)targetGraphic; ColorBlock colors = ((Selectable)obj2).colors; ((ColorBlock)(ref colors)).normalColor = ButtonOff; Color val4 = (((ColorBlock)(ref colors)).pressedColor = ButtonHover); Color highlightedColor = (((ColorBlock)(ref colors)).selectedColor = val4); ((ColorBlock)(ref colors)).highlightedColor = highlightedColor; ((ColorBlock)(ref colors)).colorMultiplier = 1f; ((Selectable)obj2).colors = colors; val.SetActive(true); return obj2; } private static void Stretch(RectTransform rect, float inset) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; rect.offsetMin = new Vector2(inset, 0f); rect.offsetMax = new Vector2(0f - inset, 0f); } private static GameObject NewObject(string name, Transform parent) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }) { layer = ((Component)parent).gameObject.layer }; val.transform.SetParent(parent, false); return val; } private static void MakeFrame(GameObject target) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) ((Graphic)target.AddComponent<Image>()).color = Fill; Outline obj = target.AddComponent<Outline>(); ((Shadow)obj).effectColor = Border; ((Shadow)obj).effectDistance = new Vector2(1f, -1f); } private static VerticalLayoutGroup NewVertical(GameObject target, float spacing) { VerticalLayoutGroup obj = target.AddComponent<VerticalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)obj).spacing = spacing; bool childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true); ((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = childControlWidth; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false; return obj; } private static Transform NewColumn(Transform parent, float width, float spacing) { GameObject obj = NewObject("Column", parent); NewVertical(obj, spacing); LayoutElement obj2 = obj.AddComponent<LayoutElement>(); float preferredWidth = (obj2.minWidth = width); obj2.preferredWidth = preferredWidth; return obj.transform; } private static Transform NewRow(Transform parent, float spacing) { GameObject obj = NewObject("Row", parent); HorizontalLayoutGroup obj2 = obj.AddComponent<HorizontalLayoutGroup>(); ((HorizontalOrVerticalLayoutGroup)obj2).spacing = spacing; ((LayoutGroup)obj2).childAlignment = (TextAnchor)3; bool childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true); ((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = childControlWidth; childControlWidth = (((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = false); ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = childControlWidth; return obj.transform; } private static TextMeshProUGUI NewText(Transform parent, string text, float size, Color color) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI obj = NewObject("Text", parent).AddComponent<TextMeshProUGUI>(); ((TMP_Text)obj).font = _font; ((TMP_Text)obj).fontSize = size; ((Graphic)obj).color = color; ((TMP_Text)obj).text = text; ((Graphic)obj).raycastTarget = false; ((TMP_Text)obj).enableWordWrapping = false; return obj; } private static TextMeshProUGUI NewWrappedText(Transform parent, string text) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) TextMeshProUGUI obj = NewText(parent, text, 9f, Dim); ((TMP_Text)obj).enableWordWrapping = true; return obj; } private static Button NewButton(Transform parent, string text, float width, Action onClick) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) GameObject val = NewObject("Button", parent); Button obj = val.AddComponent<Button>(); ((Selectable)obj).targetGraphic = (Graphic)(object)val.AddComponent<Image>(); ((UnityEvent)obj.onClick).AddListener((UnityAction)delegate { onClick(); }); LayoutElement obj2 = val.AddComponent<LayoutElement>(); float preferredHeight = (obj2.minHeight = 17f); obj2.preferredHeight = preferredHeight; preferredHeight = (obj2.minWidth = width); obj2.preferredWidth = preferredHeight; TextMeshProUGUI obj3 = NewText(val.transform, text, 10.5f, Orange); ((TMP_Text)obj3).alignment = (TextAlignmentOptions)514; RectTransform val2 = (RectTransform)((TMP_Text)obj3).transform; val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; Vector2 offsetMin = (val2.offsetMax = Vector2.zero); val2.offsetMin = offsetMin; Paint(obj, selected: false); return obj; } private static void Paint(Button button, bool selected) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) ColorBlock colors = ((Selectable)button).colors; ((ColorBlock)(ref colors)).normalColor = (selected ? Orange : ButtonOff); Color highlightedColor = (((ColorBlock)(ref colors)).selectedColor = (selected ? Orange : ButtonHover)); ((ColorBlock)(ref colors)).highlightedColor = highlightedColor; ((ColorBlock)(ref colors)).pressedColor = Orange; ((ColorBlock)(ref colors)).colorMultiplier = 1f; ((Selectable)button).colors = colors; ((Graphic)((Component)button).GetComponentInChildren<TextMeshProUGUI>()).color = (selected ? Fill : Orange); } } internal static class LevelLoaderDetails { internal static bool Installed => Chainloader.PluginInfos.ContainsKey("imabatby.lethallevelloader"); internal static string InteriorName() { ExtendedDungeonFlow currentExtendedDungeonFlow = DungeonManager.CurrentExtendedDungeonFlow; if (!((Object)(object)currentExtendedDungeonFlow != (Object)null) || string.IsNullOrWhiteSpace(currentExtendedDungeonFlow.DungeonName)) { return null; } return currentExtendedDungeonFlow.DungeonName; } internal static string MoonClocks(int dayLengthPercent) { List<string> list = (from level in PatchedContent.ExtendedLevels where (Object)(object)level.SelectableLevel != (Object)null && level.SelectableLevel.planetHasTime && level.SelectableLevel.DaySpeedMultiplier > 0f && !Mathf.Approximately(level.SelectableLevel.DaySpeedMultiplier, 1f) orderby level.SelectableLevel.DaySpeedMultiplier select level).Select(delegate(ExtendedLevel level) { float num = (float)(700 * (100 + dayLengthPercent)) / 100f / level.SelectableLevel.DaySpeedMultiplier / 60f; return level.NumberlessPlanetName + " " + num.ToString("0.#", CultureInfo.InvariantCulture) + " min"; }).ToList(); if (list.Count != 0) { return "These run at a different speed, shown here at this day length: " + string.Join(", ", list) + "."; } return "Every moon runs at normal speed."; } } [BepInPlugin("bacongamerules", "BaconGameRules", "1.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { internal const string Guid = "bacongamerules"; internal const string Version = "1.2.0"; private const string BaconFixerGuid = "baconfixer"; internal static ManualLogSource Log; private void Awake() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; if (Chainloader.PluginInfos.TryGetValue("baconfixer", out var value) && value.Metadata.Version.Major < 2) { Log.LogWarning((object)$"BaconFixer {value.Metadata.Version} already has Game Rules, so BaconGameRules stays off. Update BaconFixer to 2.0.0 or later."); return; } Harmony h = new Harmony("bacongamerules"); try { GameSetup.Apply(h, ((BaseUnityPlugin)this).Config); } catch (Exception ex) { Log.LogWarning((object)("GameSetup failed: " + ex.Message)); } try { Seeds.Apply(h); } catch (Exception ex2) { Log.LogWarning((object)("Seeds failed: " + ex2.Message)); } Log.LogInfo((object)"BaconGameRules 1.2.0 loaded"); } } public enum Rule { ScrapAmount, ScrapValue, Enemies, SpawnRate, Mines, Turrets, Traps, QuotaGrowth } public static class RulesApi { internal sealed class ExtraRule { internal string Heading; internal string Label; internal string Description; internal Func<int, ConfigEntry<int>> Entry; internal int Step; internal int Min; internal int Max; internal Func<int, string> Format; internal string[] Options; internal bool LockedOnceStarted; } public const int SaveFiles = 3; internal static readonly List<ExtraRule> ExtraRules = new List<ExtraRule>(); public static void AddFactor(Rule rule, Func<SelectableLevel, float> factor) { if (factor != null) { GameSetup.AddFactor(rule, factor); } } public static void AddRule(string heading, string label, string description, Func<int, ConfigEntry<int>> entryForFile, int step, int min, int max, Func<int, string> format = null) { if (entryForFile != null && !string.IsNullOrEmpty(label)) { ExtraRules.Add(new ExtraRule { Heading = (heading ?? "").ToUpperInvariant(), Label = label, Description = (description ?? ""), Entry = entryForFile, Step = Math.Max(1, step), Min = min, Max = Math.Max(min, max), Format = (format ?? ((Func<int, string>)((int value) => value.ToString()))) }); } } public static void AddChoice(string heading, string label, string description, Func<int, ConfigEntry<int>> entryForFile, params string[] options) { if (entryForFile != null && !string.IsNullOrEmpty(label) && options != null && options.Length != 0) { ExtraRules.Add(new ExtraRule { Heading = (heading ?? "").ToUpperInvariant(), Label = label, Description = (description ?? ""), Entry = entryForFile, Step = 1, Min = 0, Max = options.Length - 1, Format = (int value) => options[Math.Max(0, Math.Min(options.Length - 1, value))], Options = options }); } } public static void LockOnceStarted(string heading, string label) { heading = (heading ?? "").ToUpperInvariant(); foreach (ExtraRule extraRule in ExtraRules) { if (extraRule.Heading == heading && extraRule.Label == label) { extraRule.LockedOnceStarted = true; } } } public static int ScaledFor(int saveFile) { return GameSetup.ForSlot(saveFile)?.Crew ?? 4; } public static float CrewFactor(Rule rule, int saveFile) { return GameSetup.CrewFactor(rule, ScaledFor(saveFile)); } public static float Factor(Rule rule) { return GameSetup.Factor(rule, GameSetup.CurrentLevel()); } } internal static class Seeds { private const int Shown = 8; private const int Kept = 200; private const int MaxSeed = 99999999; private const string Header = "# BaconGameRules: the map seed of each landing, newest last. Date, moon, interior and seed, split by tabs."; private const string OtherPageEntry = ">SEED\nTo see this landing's map seed and the last ones. SEED and a number lands on that seed next time."; private static string _file; private static int? _next; private static bool _overrideSet; private static string _landing; private static TerminalNode _page; internal static string FileName => "bacongamerules.seeds.txt"; internal static void Apply(Harmony h) { _file = Path.Combine(Paths.ConfigPath, FileName); h.PatchAll(typeof(Seeds)); } [HarmonyPostfix] [HarmonyPatch(typeof(StartOfRound), "Awake")] private static void Reset() { _next = null; _overrideSet = false; _landing = null; } [HarmonyPostfix] [HarmonyPatch(typeof(RoundManager), "FinishGeneratingLevel")] private static void Record(RoundManager __instance) { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.currentLevel == (Object)null) { return; } string text = (LevelLoaderDetails.Installed ? LevelLoaderDetails.InteriorName() : null) ?? FlowName(__instance); string text2 = instance.randomMapSeed.ToString(CultureInfo.InvariantCulture); _landing = Highlight(text2) + " on " + instance.currentLevel.PlanetName + ", " + text; try { List<string> list = (File.Exists(_file) ? (from line in File.ReadAllLines(_file) where line.Length > 0 && line[0] != '#' select line).ToList() : new List<string>()); list.Add(string.Join("\t", DateTime.Now.ToString("yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture), instance.currentLevel.PlanetName, text, text2)); File.WriteAllLines(_file, new string[1] { "# BaconGameRules: the map seed of each landing, newest last. Date, moon, interior and seed, split by tabs." }.Concat(list.Skip(Math.Max(0, list.Count - 200)))); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Seeds: couldn't save this landing's seed to " + FileName + ": " + ex.Message)); } Plugin.Log.LogInfo((object)("Seeds: landed with seed " + text2 + " on " + instance.currentLevel.PlanetName + ", " + text)); } private static string Highlight(string seed) { return "<color=#FFD24D>" + seed + "</color>"; } private static string FlowName(RoundManager round) { DungeonFlow val = (((Object)(object)round.dungeonGenerator != (Object)null && round.dungeonGenerator.Generator != null) ? round.dungeonGenerator.Generator.DungeonFlow : null); if ((Object)(object)val == (Object)null) { return "unknown interior"; } return ((Object)val).name switch { "Level1Flow" => "Facility", "Level2Flow" => "Mansion", "Level3Flow" => "Mineshaft", _ => ((Object)val).name, }; } [HarmonyPrefix] [HarmonyPatch(typeof(StartOfRound), "StartGame")] private static void UseTypedSeed(StartOfRound __instance) { _overrideSet = false; if (_next.HasValue && ((NetworkBehaviour)__instance).IsServer && __instance.inShipPhase && !__instance.isChallengeFile && !__instance.overrideRandomSeed) { __instance.overrideRandomSeed = true; __instance.overrideSeedNumber = _next.Value; _overrideSet = true; } } [HarmonyPostfix] [HarmonyPatch(typeof(StartOfRound), "StartGame")] private static void ForgetTypedSeed(StartOfRound __instance) { if (_overrideSet) { __instance.overrideRandomSeed = false; _overrideSet = false; if (__instance.randomMapSeed == _next) { Plugin.Log.LogInfo((object)$"Seeds: landing with the typed seed {_next}"); _next = null; } } } [HarmonyPostfix] [HarmonyPatch(typeof(Terminal), "Start")] private static void AddToOtherPage(Terminal __instance) { TerminalKeyword[] allKeywords = __instance.terminalNodes.allKeywords; foreach (TerminalKeyword val in allKeywords) { if (!((Object)(object)val == (Object)null) && string.Equals(val.word, "other", StringComparison.OrdinalIgnoreCase)) { TerminalNode specialKeywordResult = val.specialKeywordResult; if ((Object)(object)specialKeywordResult != (Object)null && !specialKeywordResult.displayText.Contains(">SEED\nTo see this landing's map seed and the last ones. SEED and a number lands on that seed next time.")) { specialKeywordResult.displayText = specialKeywordResult.displayText.TrimEnd() + "\n\n>SEED\nTo see this landing's map seed and the last ones. SEED and a number lands on that seed next time.\n\n"; } break; } } } [HarmonyPrefix] [HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")] private static bool SeedCommand(Terminal __instance, ref TerminalNode __result) { if ((Object)(object)__instance.currentNode != (Object)null && __instance.currentNode.overrideOptions) { return true; } string text = __instance.screenText.text; string[] array = new string((from c in text.Substring(Math.Max(0, text.Length - __instance.textAdded)) where !char.IsPunctuation(c) select c).ToArray()).ToLowerInvariant().Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0 || array[0] != "seed") { return true; } __result = Page((array.Length > 1) ? array[1] : null); return false; } private static TerminalNode Page(string argument) { if ((Object)(object)_page == (Object)null) { _page = ScriptableObject.CreateInstance<TerminalNode>(); ((Object)_page).name = "BaconGameRules Seed"; _page.clearPreviousText = true; _page.terminalEvent = ""; _page.maxCharactersToType = 25; } _page.displayText = Text(Choose(argument)); return _page; } private static string Choose(string argument) { if (argument == null) { return null; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || !((NetworkBehaviour)instance).IsServer) { return "Only the host can pick the next landing's seed."; } if (instance.isChallengeFile) { return "The challenge moon always uses its own seed."; } switch (argument) { case "random": case "clear": case "off": case "none": _next = null; return "The next landing gets a random seed."; default: { string text = new string(argument.Where(char.IsDigit).ToArray()); if (text.Length == 0) { return "Type SEED and a number, such as SEED 424242, or SEED RANDOM."; } if (text.Length > 8 || !int.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out var result) || result < 1 || result > 99999999) { return $"Seeds go from 1 to {99999999}."; } _next = result; return $"The next landing uses seed {result}."; } } } private static string Text(string result) { StartOfRound instance = StartOfRound.Instance; StringBuilder stringBuilder = new StringBuilder("\n\nMAP SEED\n----------------------------\n\n"); if (result != null) { stringBuilder.Append(result).Append("\n\n"); } if ((Object)(object)instance != (Object)null && !instance.inShipPhase && _landing != null) { stringBuilder.Append("This landing: " + _landing + ".\n"); } if ((Object)(object)instance != (Object)null && ((NetworkBehaviour)instance).IsServer) { stringBuilder.Append(_next.HasValue ? ("Next landing: seed " + Highlight(_next.ToString()) + ", typed by you.\n") : "Next landing: random.\n"); } else { stringBuilder.Append("Next landing: the host picks it.\n"); } stringBuilder.Append("\nSEED and a number lands on that seed next time, and SEED RANDOM goes back. The same seed on the same moon gives the same interior, layout and scrap.\n"); List<string> list = Recent(); if (list.Count > 0) { stringBuilder.Append("\nLAST LANDINGS, newest first:\n"); foreach (string item in list) { stringBuilder.Append(item).Append('\n'); } stringBuilder.Append("All of them are saved in BepInEx/config/" + FileName + ".\n"); } return stringBuilder.Append('\n').ToString(); } private static List<string> Recent() { try { if (!File.Exists(_file)) { return new List<string>(); } return (from fields in (from line in File.ReadAllLines(_file) where line.Length > 0 && line[0] != '#' select line.Split('\t') into fields where fields.Length >= 4 select fields).Reverse().Take(8) select Highlight(fields[3].PadRight(9)) + " " + fields[1] + ", " + fields[2]).ToList(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Seeds: couldn't read " + FileName + ": " + ex.Message)); return new List<string>(); } } } }