Decompiled source of LethalMoonUnlocks v2.1.9

BepInEx/plugins/LethalMoonUnlocks/LethalMoonUnlocks.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LethalConstellations.ConfigManager;
using LethalConstellations.EventStuff;
using LethalConstellations.PluginCore;
using LethalLevelLoader;
using LethalMoonUnlocks.Compatibility;
using LethalMoonUnlocks.Patches;
using LethalMoonUnlocks.Util;
using LethalNetworkAPI;
using LethalQuantities;
using LethalQuantities.Json;
using LethalQuantities.Objects;
using Microsoft.CodeAnalysis;
using OpenLib.Events;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using WeatherTweaks;

[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("LethalMoonUnlocks")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Permanently unlock moons and more")]
[assembly: AssemblyFileVersion("2.1.9.0")]
[assembly: AssemblyInformationalVersion("2.1.9+64532f8d0155604a1812e32801d78d4d5d9e4035")]
[assembly: AssemblyProduct("LethalMoonUnlocks")]
[assembly: AssemblyTitle("LethalMoonUnlocks")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.1.9.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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;
		}
	}
	internal static class IsExternalInit
	{
	}
}
namespace LethalMoonUnlocks
{
	public class ConfigManager
	{
		private static string _configPath = Path.Combine(Paths.ConfigPath, "LethalMoonUnlocks.cfg");

		private static ConfigFile _configFile;

		private static int _quotaUnlockCountMin;

		private static int _quotaUnlockCountMax;

		private static int _quotaDiscountCountMin;

		private static int _quotaDiscountCountMax;

		private static int _quotaFullDiscountCountMin;

		private static int _quotaFullDiscountCountMax;

		private static int _quotaDiscoveryCountMin;

		private static int _quotaDiscoveryCountMax;

		private static int _travelDiscoveryCountMin;

		private static int _travelDiscoveryCountMax;

		private static int _newDayDiscoveryCountMin;

		private static int _newDayDiscoveryCountMax;

		private static int _salesRateMin;

		private static int _salesRateMax;

		public static ConfigManager Instance { get; private set; }

		public static bool ResetWhenFired { get; private set; }

		public static bool DisplayTerminalTags { get; private set; }

		public static bool ShowTagInOrbit { get; private set; }

		public static bool ShowTagNewDiscovery { get; private set; }

		public static bool ShowTagExplored { get; private set; }

		public static bool ShowTagUnlockDiscount { get; private set; }

		public static bool ShowTagPermanentDiscovery { get; private set; }

		public static bool ShowTagSale { get; private set; }

		public static bool ShowTagGroups { get; private set; }

		public static bool ShowAlerts { get; private set; }

		public static bool ChatMessages { get; private set; }

		public static bool UnlockMode { get; private set; }

		public static int UnlocksResetAfterVisits { get; private set; }

		public static bool UnlocksResetAfterVisitsPermDiscovery { get; private set; }

		public static bool QuotaUnlocks { get; private set; }

		public static int QuotaUnlockChance { get; private set; }

		public static int QuotaUnlockCount => Random.Range(_quotaUnlockCountMin, _quotaUnlockCountMax + 1);

		public static int QuotaUnlockMaxCount { get; private set; }

		public static int QuotaUnlockMaxPrice { get; private set; }

		public static bool DiscountMode { get; private set; }

		private static string DiscountsString { get; set; }

		public static List<int> Discounts
		{
			get
			{
				string[] array = DiscountsString.Split(',', StringSplitOptions.RemoveEmptyEntries);
				List<int> list = new List<int>();
				string[] array2 = array;
				foreach (string s in array2)
				{
					list.Add(int.Parse(s));
				}
				return list;
			}
		}

		public static int DiscountsCount => Discounts.Count();

		public static int DiscountsResetAfterVisits { get; private set; }

		public static bool DiscountsResetAfterVisitsPermDiscovery { get; private set; }

		public static bool QuotaDiscounts { get; private set; }

		public static int QuotaDiscountChance { get; private set; }

		public static int QuotaDiscountCount => Random.Range(_quotaDiscountCountMin, _quotaDiscountCountMax + 1);

		public static int QuotaDiscountMaxCount { get; private set; }

		public static int QuotaDiscountMaxPrice { get; private set; }

		public static bool QuotaFullDiscounts { get; private set; }

		public static int QuotaFullDiscountChance { get; private set; }

		public static int QuotaFullDiscountCount => Random.Range(_quotaFullDiscountCountMin, _quotaFullDiscountCountMax + 1);

		public static int QuotaFullDiscountMaxCount { get; private set; }

		public static int QuotaFullDiscountMaxPrice { get; private set; }

		public static bool DiscoveryMode { get; private set; }

		private static string DiscoveryWhitelist { get; set; }

		public static List<string> DiscoveryWhitelistMoons => DiscoveryWhitelist.Split(",", StringSplitOptions.RemoveEmptyEntries).ToList();

		public static bool DiscoveryKeepUnlocks { get; private set; }

		public static bool DiscoveryKeepDiscounts { get; private set; }

		public static int DiscoveryFreeCountBase { get; private set; }

		public static int DiscoveryFreeCountIncreaseBy { get; private set; }

		public static int DiscoveryDynamicFreeCountBase { get; private set; }

		public static int DiscoveryDynamicFreeCountIncreaseBy { get; private set; }

		public static int DiscoveryPaidCountBase { get; private set; }

		public static int DiscoveryPaidCountIncreaseBy { get; private set; }

		public static int PermanentlyDiscoverFreeMoonsOnLanding { get; private set; }

		public static int PermanentlyDiscoverPaidMoonsOnLanding { get; private set; }

		public static bool PermanentlyDiscoverHiddenMoonsOnVisit { get; private set; }

		public static bool DiscoveryShuffleEveryDay { get; private set; }

		public static bool DiscoveryNeverShuffle { get; private set; }

		public static bool QuotaDiscoveries { get; private set; }

		public static int QuotaDiscoveryChance { get; private set; }

		public static int QuotaDiscoveryCount => Random.Range(_quotaDiscoveryCountMin, _quotaDiscoveryCountMax + 1);

		public static bool QuotaDiscoveryPermanent { get; private set; }

		public static bool QuotaDiscoveryCheapestGroup { get; private set; }

		public static bool QuotaDiscoveryCheapestGroupFallback { get; private set; }

		public static bool QuotaDiscoveryCheapestConstellation { get; private set; }

		public static bool TravelDiscoveries { get; private set; }

		public static int TravelDiscoveryChance { get; private set; }

		public static int TravelDiscoveryCount => Random.Range(_travelDiscoveryCountMin, _travelDiscoveryCountMax + 1);

		public static bool TravelDiscoveryPermanent { get; private set; }

		public static bool TravelDiscoveryMatchGroup { get; private set; }

		public static bool TravelDiscoveryMatchGroupFallback { get; private set; }

		public static bool NewDayDiscoveries { get; private set; }

		public static int NewDayDiscoveryChance { get; private set; }

		public static int NewDayDiscoveryCount => Random.Range(_newDayDiscoveryCountMin, _newDayDiscoveryCountMax + 1);

		public static bool NewDayDiscoveryPermanent { get; private set; }

		public static bool NewDayDiscoveryMatchGroup { get; private set; }

		public static bool NewDayDiscoveryMatchGroupFallback { get; private set; }

		public static bool Sales { get; private set; }

		public static int SalesChance { get; private set; }

		public static bool SalesShuffleDaily { get; private set; }

		public static int SalesRate => Random.Range(_salesRateMin, _salesRateMax);

		public static bool CheapMoonBiasIgnorePriceChanges { get; private set; }

		public static bool CheapMoonBiasPaidRotation { get; private set; }

		public static float CheapMoonBiasPaidRotationValue { get; private set; }

		public static bool CheapMoonBiasQuotaDiscovery { get; private set; }

		public static float CheapMoonBiasQuotaDiscoveryValue { get; private set; }

		public static bool CheapMoonBiasNewDayDiscovery { get; private set; }

		public static float CheapMoonBiasNewDayDiscoveryValue { get; private set; }

		public static bool CheapMoonBiasTravelDiscovery { get; private set; }

		public static float CheapMoonBiasTravelDiscoveryValue { get; private set; }

		public static bool CheapMoonBiasQuotaUnlock { get; private set; }

		public static float CheapMoonBiasQuotaUnlockValue { get; private set; }

		public static bool CheapMoonBiasQuotaDiscount { get; private set; }

		public static float CheapMoonBiasQuotaDiscountValue { get; private set; }

		public static bool CheapMoonBiasQuotaFullDiscount { get; private set; }

		public static float CheapMoonBiasQuotaFullDiscountValue { get; private set; }

		public static string MoonGroupMatchingMethod { get; private set; }

		public static int MoonGroupMatchingPriceRange { get; private set; }

		private static string MoonGroupMatchingCustom { get; set; }

		public static Dictionary<string, List<string>> MoonGroupMatchingCustomDict { get; private set; }

		private static bool MoonGroupMatchingCustomHelper { get; set; }

		public static int TerminalTagLineWidth { get; set; }

		public static bool TerminalFontSizeOverride { get; set; }

		public static float TerminalFontSize { get; set; }

		public static int TerminalScrollAmount { get; set; }

		public static bool PreferLQRisk { get; private set; }

		public static bool MalfunctionsNavigation { get; private set; }

		public static bool AlertMessageQueueing { get; private set; }

		public static bool LethalConstellationsOverridePrice { get; private set; }

		public ConfigManager()
		{
			if (Instance == null)
			{
				Instance = this;
			}
			Plugin.Instance.Mls.LogInfo((object)"ConfigManager created");
			RefreshConfig();
		}

		public static void RefreshConfig()
		{
			Plugin.Instance.Mls.LogInfo((object)"Refreshing config..");
			_configFile = null;
			EnsureConfigExists();
			RefreshValues();
		}

		public static Dictionary<string, List<string>> ParseCustomMoonGroups()
		{
			if (MoonGroupMatchingCustomHelper)
			{
				Plugin.Instance.Mls.LogWarning((object)"Printing available moon names for custom moon groups..");
				Plugin.Instance.Mls.LogWarning((object)(string.Join(", ", from level in PatchedContent.ExtendedLevels
					where level.NumberlessPlanetName != "Gordion" && level.NumberlessPlanetName != "Liquidation"
					select ((Object)level).name) ?? ""));
			}
			Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();
			if (MoonGroupMatchingCustom == string.Empty)
			{
				Plugin.Instance.Mls.LogInfo((object)"No custom moon group defined. Skip parsing..");
				return dictionary;
			}
			string[] array = MoonGroupMatchingCustom.Split('|');
			foreach (string obj in array)
			{
				string text = obj.Split(":").First().Trim();
				string text2 = obj.Split(':').Last().Trim();
				string[] array2 = text2.Split(",");
				List<string> list = new List<string>();
				string[] array3 = array2;
				foreach (string text3 in array3)
				{
					list.Add(text3.Trim());
				}
				if (text == null || text == string.Empty)
				{
					Plugin.Instance.Mls.LogWarning((object)"Couldn't parse custom moon group name. Make sure you're using the correct format!");
					continue;
				}
				if (text2 == string.Empty || list.Count == 0)
				{
					Plugin.Instance.Mls.LogWarning((object)"Couldn't parse custom moon group! Name null or empty or members not found!");
					continue;
				}
				Plugin.Instance.Mls.LogInfo((object)("Parsed custom moon group: Name = " + text + ", Members = [ " + string.Join(", ", list) + " ]"));
				dictionary[text] = list;
			}
			return dictionary;
		}

		private static void RefreshValues()
		{
			//IL_0b6e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b78: Expected O, but got Unknown
			ResetWhenFired = GetConfigValue("1 - General settings", "Reset when fired", defaultValue: true, "Reset your progress when being fired. Unlocks, Discounts, and permanently discovered moons will all be wiped.\nUnlocks, Discounts, Permanently Discovered moons, ..  all of it will persist unless you create a new save.\nThe only exception to this option is the base selection of moons in Discovery Mode.");
			ChatMessages = GetConfigValue("1 - General settings", "Show chat messages", defaultValue: true, "When enabled, LethalMoonUnlocks will send messages to the in-game chat whenever something relevant happens.");
			ShowAlerts = GetConfigValue("1 - General settings", "Show alert messages", defaultValue: false, "When enabled, LethalMoonUnlocks will display alert messages whenever something relevant happens.");
			DisplayTerminalTags = GetConfigValue("1.1 - Terminal moon tags", "Display tags in terminal", defaultValue: false, "When enabled, LethalMoonUnlocks will display additional tags in the Terminal moon catalogue.\nThese tags will indicate various conditions, such as a moon being unlocked or discounted, being on sale, etc.\nIf custom moon groups or matching by LLL tag are enabled, you'll also see the custom groups or LLL tags a moon is associated with.\nNOTE: At this time additional tags will only show in the standard LLL moon catalogue and TerminalFormatter. Any other mod replacing the 'moons' command will probably cause issues.");
			ShowTagInOrbit = GetConfigValue("1.1 - Terminal moon tags", "In orbit tag", defaultValue: true, "Display a tag to indicate the moon you're currently orbiting.");
			ShowTagExplored = GetConfigValue("1.1 - Terminal moon tags", "Exploration tag", defaultValue: true, "Display a tag to indicate which moons have not been landed on yet. After landing once, it will keep track of how many times you've landed in total.");
			ShowTagUnlockDiscount = GetConfigValue("1.1 - Terminal moon tags", "Unlock discount tag", defaultValue: true, "Display a tag to indicate Unlocks and Discounts as well as how many routes are left before they expire.");
			ShowTagNewDiscovery = GetConfigValue("1.1 - Terminal moon tags", "New discovery tag", defaultValue: true, "Discovery Mode only: display a tag to indicate which moons are new discoveries i.e. available in the moon catalogue for the first time. The tag will vanish when you route to the moon or the moon catalogue is shuffled.");
			ShowTagPermanentDiscovery = GetConfigValue("1.1 - Terminal moon tags", "Permanent discovery tag", defaultValue: true, "Discovery Mode only: display a tag to indicate permanently discovered moons.\nDisplays as [PINNED].");
			ShowTagSale = GetConfigValue("1.1 - Terminal moon tags", "Sales tag", defaultValue: true, "Moon Sales only: display a tag to indicate which moons are on sale, as well as the percentage of the sale.");
			ShowTagGroups = GetConfigValue("1.1 - Terminal moon tags", "Group tag", defaultValue: true, "Moon Group Matching only: display a tag to indicate groups a moon belongs to. Limited to custom group, LethalConstellations and LLL tag matching methods.");
			UnlockMode = GetConfigValue("2 - Unlock Mode (Default)", "Enable Unlock Mode", defaultValue: true, "Unlock Mode is the default mode, akin to the original Permanent Moons mod. In Unlock Mode, when you buy a paid moon, it will be 'unlocked'.\nOnce unlocked, moons are completely free, and by default, will stay free permanently.\nNOTE: This setting and all settings relating to Unlocks will have no effect if Discount Mode is enabled!");
			UnlocksResetAfterVisits = GetConfigValue("2 - Unlock Mode (Default)", "Unlocks expire", 0, "Unlocks will expire after a set number of free routes, after which they will become paid again.\nSet to 0 to disable this feature.");
			DiscoveryKeepUnlocks = GetConfigValue("2 - Unlock Mode (Default)", "Unlocked moons are permanently discovered", defaultValue: false, "Discovery Mode only: Every unlocked moon is also permanently discovered i.e. added to the moon catalogue on top of your base selection.");
			UnlocksResetAfterVisitsPermDiscovery = GetConfigValue("2 - Unlock Mode (Default)", "Reset permanent discovery on unlock expiry", defaultValue: false, "Discovery Mode only: Reset a moon's permanent discovery status when its unlock expires.\nThis is the only way permanent discoveries can vanish during a run in Unlock Mode.\n");
			QuotaUnlocks = GetConfigValue("2.1 - Quota Unlocks", "Enable Quota Unlocks", defaultValue: false, "Quota Unlocks are rewarded for meeting the quota. When triggered, Quota Unlocks will grant you one or more unlocks for free.\nThe moons that are unlocked are randomly selected.");
			QuotaUnlockChance = GetConfigValue("2.1 - Quota Unlocks", "Quota Unlock trigger chance", 100, "The chance to trigger a Quota Unlock every time you meet the quota.", new AcceptableValueRange<int>(0, 100));
			_quotaUnlockCountMin = GetConfigValue("2.1 - Quota Unlocks", "Minimum unlocked moon count", 1, "The minimum number of moons that will be unlocked each time a Quota Unlock is triggered.", new AcceptableValueRange<int>(1, 10));
			_quotaUnlockCountMax = GetConfigValue("2.1 - Quota Unlocks", "Maximum unlocked moon count", 1, "The maximum number of moons that will be unlocked each time a Quota Unlock is triggered.", new AcceptableValueRange<int>(1, 10));
			QuotaUnlockMaxPrice = GetConfigValue("2.1 - Quota Unlocks", "Maximum moon price to unlock", 0, "Only consider moons up to this price to be unlocked.\nSet to 0 to disable this feature.");
			QuotaUnlockMaxCount = GetConfigValue("2.1 - Quota Unlocks", "Limit number of unlocks", 0, "Limit how many Quota Unlocks you can receive during a run. After reaching the limit, Quota Unlocks will no longer be granted.\nSet to 0 to disable this feature.");
			DiscountMode = GetConfigValue("3 - Discount Mode", "Enable Discount Mode", defaultValue: false, "In Discount Mode, Unlocks are replaced with Discounts.\nEach time you route to a paid moon, you will unlock the next available discount rate until the final discount is reached.\nThe discount rates are fully customizable.");
			DiscountsString = GetConfigValue("3 - Discount Mode", "Discount rates", "50,75,100", "The discount rates that are applied to moon prices as a % off of the original routing price.\nFor example, '50,75,100', would make each moon 50% off after the first purchase, 75% off after the second purchase, and free after the third purchase.\nDiscount rates are separated by commas and can contain any number of rates");
			Plugin.Instance.Mls.LogInfo((object)("Discount rates (% off): " + string.Join(", ", Discounts.Select((int discount) => discount + "%"))));
			DiscountsResetAfterVisits = GetConfigValue("3 - Discount Mode", "Discounts expire", 0, "Discounts will expire after a set number of free routes, after which they will return to their original price.\nSet to 0 to disable this feature.\nNOTE: The final discount rate must be set to '100' for this to work!");
			DiscoveryKeepDiscounts = GetConfigValue("3 - Discount Mode", "Discounted moons are permanently discovered", defaultValue: false, "Discovery Mode only: Every discounted moon is also permanently discovered i.e. added to the moon catalogue on top of your base selection.");
			DiscountsResetAfterVisitsPermDiscovery = GetConfigValue("3 - Discount Mode", "Reset permanent discoveries on discount expiry", defaultValue: false, "Discovery Mode only: Reset a moon's permanent discovery status when its discount expires.\nThis is the only way permanent discoveries can vanish during a run in Discount Mode.\n");
			QuotaDiscounts = GetConfigValue("3.1 - Quota Discounts", "Enable Quota Discounts", defaultValue: false, "Quota Discounts are rewarded for meeting the quota. When triggered Quota Discounts will grant you one or more discounts for free.\nThe moons that are discounted are randomly selected.");
			QuotaDiscountChance = GetConfigValue("3.1 - Quota Discounts", "Quota Discount trigger chance", 100, "The chance to trigger a Quota Discount every time you meet the quota.\n", new AcceptableValueRange<int>(0, 100));
			_quotaDiscountCountMin = GetConfigValue("3.1 - Quota Discounts", "Minimum discounted moon count", 1, "The minimum number of moons that will receive a discount each time a Quota Discount is triggered.", new AcceptableValueRange<int>(1, 10));
			_quotaDiscountCountMax = GetConfigValue("3.1 - Quota Discounts", "Maximum discounted moon count", 1, "The maximum number of moons that will receive a discount each time a Quota Discount is triggered.", new AcceptableValueRange<int>(1, 10));
			QuotaDiscountMaxPrice = GetConfigValue("3.1 - Quota Discounts", "Maximum moon price to discount", 0, "Only consider moons up to this price to receive a discount.\nSet to 0 to disable this feature");
			QuotaDiscountMaxCount = GetConfigValue("3.1 - Quota Discounts", "Limit number of discounts", 0, "Limit how many Quota Discounts you can receive during a run. After reaching the limit, Quota Discounts will no longer be granted.\nSet to 0 to disable this feature");
			QuotaFullDiscounts = GetConfigValue("3.2 - Quota Full Discounts", "Enable Quota Full Discounts", defaultValue: false, "Quota Full Discounts are rewarded for meeting the quota. When triggered, Quota Full Discounts will apply the final discount rate to one or more moons for free.\nThe moons that are discounted are randomly selected.");
			QuotaFullDiscountChance = GetConfigValue("3.2 - Quota Full Discounts", "Quota Full Discount trigger chance", 100, "The chance to trigger a Quota Full Discount every time you meet the quota.", new AcceptableValueRange<int>(0, 100));
			_quotaFullDiscountCountMin = GetConfigValue("3.2 - Quota Full Discounts", "Minimum fully discounted moon count", 1, "The minimum number of moons that will receive a full discount each time a Quota Full Discount is triggered.", new AcceptableValueRange<int>(1, 10));
			_quotaFullDiscountCountMax = GetConfigValue("3.2 - Quota Full Discounts", "Maximum fully discounted moon count", 1, "The maximum number of moons that will receive a full discount each time a Quota Full Discount is triggered.", new AcceptableValueRange<int>(1, 10));
			QuotaFullDiscountMaxPrice = GetConfigValue("3.2 - Quota Full Discounts", "Maximum moon price to fully discount", 0, "Only consider moons up to this price to receive a full discount.\nSet to 0 to disable this feature");
			QuotaFullDiscountMaxCount = GetConfigValue("3.2 - Quota Full Discounts", "Limit number of full discounts", 0, "Limit how many Quota Full Discounts you can receive during a run. After reaching the limit, Quota Full Discounts will no longer be granted.\nSet to 0 to disable this feature");
			DiscoveryMode = GetConfigValue("4 - Discovery Mode", "Enable Discovery Mode", defaultValue: false, "In Discovery Mode, you start with a limited selection of moons in the Terminal's moon catalogue.\nBy default, this base selection of moons will be shuffled after every quota, and can also be configured to expand over time.\nThere are also various options to discover additional moons as you play.\nPermanently discovered moons are added to the moon catalogue on top of the base selection, and are not lost on shuffle.");
			DiscoveryNeverShuffle = GetConfigValue("4 - Discovery Mode", "Never shuffle", defaultValue: false, "Never shuffle the rotation of moons available in the moon catalogue.\nNew moons must be discovered through other means, but once discovered, they won't vanish, since the selection is never shuffled.\nNOTE: Overrides the 'Shuffle every day' option.");
			DiscoveryShuffleEveryDay = GetConfigValue("4 - Discovery Mode", "Shuffle every day", defaultValue: false, "Shuffle the rotation of moons available in the moon catalogue every day, instead of after every quota.");
			DiscoveryWhitelist = GetConfigValue("4 - Discovery Mode", "Whitelist", "", "List of moons to keep discovered at all times.\nFor example, 'Experimentation, Assurance, Vow' would make these three moons start out as permanently discovered on every run.\nMoon names must be separated by commas and must be exact matches. You can print the moon names to console/log by using the option in 'Advanced Settings'.");
			DiscoveryFreeCountBase = GetConfigValue("4 - Discovery Mode", "Free moons base count", 1, "The base amount of randomly selected free moons available in the moon catalogue.\nNOTE: 'Free' only considers moons that are free by default, or configured to be free. Moons that are free due to unlocks or discounts are excluded!");
			DiscoveryDynamicFreeCountBase = GetConfigValue("4 - Discovery Mode", "Dynamic free moons base count", 2, "The base amount of randomly selected dynamic free moons available in the moon catalogue.\nNOTE: 'Dynamic free' considers moons that are free due to unlocks or discounts in addition to those that are free by default, or configured to be free.");
			DiscoveryPaidCountBase = GetConfigValue("4 - Discovery Mode", "Paid moons base count", 3, "The base amount of randomly selected paid moons available in the moon catalogue.\nThis is your paid moon rotation and typically the main way to discover new moons to buy - earning unlocks and discounts as you progress.");
			DiscoveryFreeCountIncreaseBy = GetConfigValue("4 - Discovery Mode", "Increase free moon count on shuffle", 0, "The amount of randomly selected free moons added to the rotation each time it's shuffled.\nSet to 0 to disable this feature.");
			DiscoveryDynamicFreeCountIncreaseBy = GetConfigValue("4 - Discovery Mode", "Increase dynamic free moon count on shuffle by", 0, "The amount of randomly selected dynamic free moons added to the rotation each time it's shuffled.\nSet to 0 to disable this feature.");
			DiscoveryPaidCountIncreaseBy = GetConfigValue("4 - Discovery Mode", "Increase paid moon count on shuffle", 0, "The amount of randomly selected paid moons added to the rotation each time it's shuffled.\nSet to 0 to disable this feature.");
			PermanentlyDiscoverFreeMoonsOnLanding = GetConfigValue("4 - Discovery Mode", "Landings required to permanently discover free moons", -1, "Any free moon will be permanently discovered after a set amount of landings.\nSet to -1 to disable this feature.\nNOTE: A value of 0 makes every free moon ever discovered in any way permanently discovered. Not recommended.");
			PermanentlyDiscoverPaidMoonsOnLanding = GetConfigValue("4 - Discovery Mode", "Landings required to permanently discover paid moons", -1, "Any free moon will be permanently discovered after a set amount of landings.\nSet to -1 to disable this feature.\nNOTE: A value of 0 makes every paid moon ever discovered in any way permanently discovered. Not recommended.");
			PermanentlyDiscoverHiddenMoonsOnVisit = GetConfigValue("4 - Discovery Mode", "Permanently discover hidden moons after routing", defaultValue: false, "Any hidden (LLL config e.g. Embrion) will be permanently discovered after routed to once.");
			QuotaDiscoveries = GetConfigValue("4.1 - Quota Discoveries", "Enable Quota Discoveries", defaultValue: false, "Quota Discoveries grant additional moon discoveries when a new quota begins.\nThe moons that are discovered are randomly selected.");
			QuotaDiscoveryChance = GetConfigValue("4.1 - Quota Discoveries", "Quota Discovery trigger chance", 100, "The chance to trigger a Quota Discovery every time you meet the quota.", new AcceptableValueRange<int>(0, 100));
			_quotaDiscoveryCountMin = GetConfigValue("4.1 - Quota Discoveries", "Minimum quota discovery moon count", 1, "The minimum number of moons that will be discovered each time a Quota Discovery is triggered.", new AcceptableValueRange<int>(1, 10));
			_quotaDiscoveryCountMax = GetConfigValue("4.1 - Quota Discoveries", "Maximum quota discovery moon count", 1, "The maximum number of moons that will be discovered each time a Quota Discovery is triggered.", new AcceptableValueRange<int>(1, 10));
			QuotaDiscoveryPermanent = GetConfigValue("4.1 - Quota Discoveries", "Quota Discoveries are permanent", defaultValue: false, "Moons discovered through Quota Discoveries will stay permanently discovered i.e. they won't vanish on shuffle.");
			QuotaDiscoveryCheapestGroup = GetConfigValue("4.1 - Quota Discoveries", "Quota Discovery match cheapest group", defaultValue: false, "Only considers moons from the group/constellation that has the currently cheapest undiscovered moon.\nCan effectively discover the 'next tier' or group of moons. Set counts high to discover the entire group.\nNOTE: Highly recommended to only use this with 'Quota Discoveries are permanent' or 'Never shuffle'!");
			QuotaDiscoveryCheapestGroupFallback = GetConfigValue("4.1 - Quota Discoveries", "Quota Discovery match cheapest group fallback", defaultValue: true, "When enabled will fallback to selecting from all discoverable moons when no moons could be matched.\nNOTE: Only relevant when you have moons that are not assigned to any group/constellation.");
			QuotaDiscoveryCheapestConstellation = GetConfigValue("4.1 - Quota Discoveries", "Quota Discovery match cheapest constellation", defaultValue: false, "Only consider moons of the cheapest constellation. Overrides behaviour of 'match cheapest group'. \nNOTE: Match cheapest group needs to be enabled.");
			TravelDiscoveries = GetConfigValue("4.2 - Travel Discoveries", "Enable Travel Discoveries", defaultValue: false, "Travel Discoveries grant additional moon discoveries when routing to a paid moon\nThe moons that are discovered are randomly selected.");
			TravelDiscoveryChance = GetConfigValue("4.2 - Travel Discoveries", "Travel Discovery trigger chance", 20, "The chance to trigger a Travel Discovery every time you route to a paid moon.", new AcceptableValueRange<int>(0, 100));
			_travelDiscoveryCountMin = GetConfigValue("4.2 - Travel Discoveries", "Minimum travel discovery moon count", 1, "The minimum number of moons that will be discovered each time a Travel Discovery is triggered.", new AcceptableValueRange<int>(1, 10));
			_travelDiscoveryCountMax = GetConfigValue("4.2 - Travel Discoveries", "Maximum travel discovery moon count", 1, "The maximum number of moons that will be discovered each time a Travel Discovery is triggered.", new AcceptableValueRange<int>(1, 10));
			TravelDiscoveryPermanent = GetConfigValue("4.2 - Travel Discoveries", "Travel Discoveries are permanent", defaultValue: false, "Moons discovered through Travel Discoveries will stay permanently discovered i.e. they won't vanish on shuffle.");
			TravelDiscoveryMatchGroup = GetConfigValue("4.2 - Travel Discoveries", "Travel Discovery group matching", defaultValue: false, "Only consider moons of the same group you're routing to for Travel Discoveries.");
			TravelDiscoveryMatchGroupFallback = GetConfigValue("4.2 - Travel Discoveries", "Travel Discovery group matching fallback", defaultValue: true, "When enabled will fallback to selecting from all discoverable moons when no moons could be matched.\nNOTE: It is recommended to keep this on for matching by exact price but with other methods you might prefer to turn it off.");
			NewDayDiscoveries = GetConfigValue("4.3 - New Day Discoveries", "Enable New Day Discoveries", defaultValue: false, "New Day Discoveries grant additional moon discoveries at the start of a new day.\nThe moons that are discovered are randomly selected.");
			NewDayDiscoveryChance = GetConfigValue("4.3 - New Day Discoveries", "New Day Discovery trigger chance", 20, "The chance to trigger a New Day Discovery at the start of a new day.\nMake it a random occurence or guaranteed.", new AcceptableValueRange<int>(0, 100));
			_newDayDiscoveryCountMin = GetConfigValue("4.3 - New Day Discoveries", "Minimum new day discovery moon count", 1, "The minimum number of moons to be discovered each time a New Day Discovery is granted.", new AcceptableValueRange<int>(1, 10));
			_newDayDiscoveryCountMax = GetConfigValue("4.3 - New Day Discoveries", "Maximum new day discovery moon count", 1, "The maximum number of moons to be discovered each time a New Day Discovery is granted.", new AcceptableValueRange<int>(1, 10));
			NewDayDiscoveryPermanent = GetConfigValue("4.3 - New Day Discoveries", "New Day Discoveries are permanent", defaultValue: false, "Moons discovered through New Day Discoveries will stay permanently discovered i.e. they won't vanish on shuffle.");
			NewDayDiscoveryMatchGroup = GetConfigValue("4.3 - New Day Discoveries", "New Day Discovery group matching", defaultValue: false, "Only consider moons of the same group as the moon you're currently orbiting for New Day Discoveries.");
			NewDayDiscoveryMatchGroupFallback = GetConfigValue("4.3 - New Day Discoveries", "New Day Discovery group matching fallback", defaultValue: true, "When enabled will fallback to selecting from all discoverable moons when no moons could be matched.\nNOTE: It is recommended to keep this on for matching by exact price but with other methods you might prefer to turn it off.");
			Sales = GetConfigValue("5 - Moon Sales", "Moon Sales", defaultValue: false, "Each moon has a chance to go on sale for a reduced routing price.\nBy default, Moon Sales are shuffled after every quota. Only non-free moons can go on sale.\nNOTE: These sales are separate from discounts received via Discount Mode.");
			SalesShuffleDaily = GetConfigValue("5 - Moon Sales", "Shuffle sales daily", defaultValue: false, "Shuffle moon sales daily, instead of after every quota");
			SalesChance = GetConfigValue("5 - Moon Sales", "Moon Sale chance", 20, "The chance for each moon to go on sale every time sales are shuffled.", new AcceptableValueRange<int>(0, 100));
			_salesRateMin = GetConfigValue("5 - Moon Sales", "Minimum sale percent", 5, "The minimum sale percentage a moon can receive.", new AcceptableValueRange<int>(0, 100));
			_salesRateMax = GetConfigValue("5 - Moon Sales", "Maximum sale percent", 30, "The maximum sale percentage a moon can receive", new AcceptableValueRange<int>(1, 100));
			GetConfigValue("6 - Advanced settings", "I have read this", "false", "This section contains advanced configuration options for various features of the mod. Incorrectly tweaking these might cause unexpected behaviour!\nThis setting has no effect.");
			CheapMoonBiasPaidRotation = GetConfigValue("6.1 - Cheap Moon Bias", "Discovery Mode paid rotation", defaultValue: true, "Use Cheap Moon Bias when selecting moons for the paid moon rotation when it's shuffled.");
			CheapMoonBiasPaidRotationValue = GetConfigValue("6.1 - Cheap Moon Bias", "Discovery Mode paid rotation bias value", 0.66f, "Set bias value to adjust how heavily cheap moons are preferred.\nNOTE: the bias is exponential to the inverse proportion of moon price to the total of all moon prices. Let's say we have Moon A (100 credits) and Moon B (400 credits).\nB is four times the price of A => Weight of A = (4^bias) * weight of B. So at 1.0 A is four times the chance of B, at 2.0 16 times, at 0.5 sqrt(4) = 2 times and at 0.0 both have equal weights.", new AcceptableValueRange<float>(0f, 2f));
			CheapMoonBiasQuotaDiscovery = GetConfigValue("6.1 - Cheap Moon Bias", "Quota Discovery", defaultValue: true, "Use Cheap Moon Bias when selecting moons during Quota Discovery.");
			CheapMoonBiasQuotaDiscoveryValue = GetConfigValue("6.1 - Cheap Moon Bias", "Quota Discovery bias value", 0.66f, "Set bias value to adjust how heavily cheap moons are preferred.\nNOTE: the bias is exponential to the inverse proportion of moon price to the total of all moon prices. Let's say we have Moon A (100 credits) and Moon B (400 credits).\nB is four times the price of A => Weight of A = (4^bias) * weight of B. So at 1.0 A is four times the chance of B, at 2.0 16 times, at 0.5 sqrt(4) = 2 times and at 0.0 both have equal weights.", new AcceptableValueRange<float>(0f, 2f));
			CheapMoonBiasTravelDiscovery = GetConfigValue("6.1 - Cheap Moon Bias", "Travel Discovery", defaultValue: true, "Use Cheap Moon Bias when selecting moons to discover during Travel Discovery.");
			CheapMoonBiasTravelDiscoveryValue = GetConfigValue("6.1 - Cheap Moon Bias", "Travel Discovery bias value", 0.66f, "Set bias value to adjust how heavily cheap moons are preferred.\nNOTE: the bias is exponential to the inverse proportion of moon price to the total of all moon prices. Let's say we have Moon A (100 credits) and Moon B (400 credits).\nB is four times the price of A => Weight of A = (4^bias) * weight of B. So at 1.0 A is four times the chance of B, at 2.0 16 times, at 0.5 sqrt(4) = 2 times and at 0.0 both have equal weights.", new AcceptableValueRange<float>(0f, 2f));
			CheapMoonBiasNewDayDiscovery = GetConfigValue("6.1 - Cheap Moon Bias", "New Day Discovery", defaultValue: true, "Use Cheap Moon Bias when selecting moons during New Day Discovery.");
			CheapMoonBiasNewDayDiscoveryValue = GetConfigValue("6.1 - Cheap Moon Bias", "New Day Discovery bias value", 0.66f, "Set bias value to adjust how heavily cheap moons are preferred.\nNOTE: the bias is exponential to the inverse proportion of moon price to the total of all moon prices. Let's say we have Moon A (100 credits) and Moon B (400 credits).\nB is four times the price of A => Weight of A = (4^bias) * weight of B. So at 1.0 A is four times the chance of B, at 2.0 16 times, at 0.5 sqrt(4) = 2 times and at 0.0 both have equal weights.", new AcceptableValueRange<float>(0f, 2f));
			CheapMoonBiasQuotaUnlock = GetConfigValue("6.1 - Cheap Moon Bias", "Quota Unlock", defaultValue: true, "Use Cheap Moon Bias when selecting moons during Quota Unlocks.");
			CheapMoonBiasQuotaUnlockValue = GetConfigValue("6.1 - Cheap Moon Bias", "Quota Unlock bias value", 0.66f, "Set bias value to adjust how heavily cheap moons are preferred.\nNOTE: the bias is exponential to the inverse proportion of moon price to the total of all moon prices. Let's say we have Moon A (100 credits) and Moon B (400 credits).\nB is four times the price of A => Weight of A = (4^bias) * weight of B. So at 1.0 A is four times the chance of B, at 2.0 16 times, at 0.5 sqrt(4) = 2 times and at 0.0 both have equal weights.", new AcceptableValueRange<float>(0f, 2f));
			CheapMoonBiasQuotaDiscount = GetConfigValue("6.1 - Cheap Moon Bias", "Quota Discount", defaultValue: true, "Use Cheap Moon Bias when selecting moons during Quota Discounts.");
			CheapMoonBiasQuotaDiscountValue = GetConfigValue("6.1 - Cheap Moon Bias", "Quota Discount bias value", 0.66f, "Set bias value to adjust how heavily cheap moons are preferred.\nNOTE: the bias is exponential to the inverse proportion of moon price to the total of all moon prices. Let's say we have Moon A (100 credits) and Moon B (400 credits).\nB is four times the price of A => Weight of A = (4^bias) * weight of B. So at 1.0 A is four times the chance of B, at 2.0 16 times, at 0.5 sqrt(4) = 2 times and at 0.0 both have equal weights.", new AcceptableValueRange<float>(0f, 2f));
			CheapMoonBiasQuotaFullDiscount = GetConfigValue("6.1 - Cheap Moon Bias", "Quota Full Discount", defaultValue: true, "Use Cheap Moon Bias when selecting moons during Quota Full Discounts.");
			CheapMoonBiasQuotaFullDiscountValue = GetConfigValue("6.1 - Cheap Moon Bias", "Quota Full Discount bias value", 0.66f, "Set bias value to adjust how heavily cheap moons are preferred.\nNOTE: the bias is exponential to the inverse proportion of moon price to the total of all moon prices. Let's say we have Moon A (100 credits) and Moon B (400 credits).\nB is four times the price of A => Weight of A = (4^bias) * weight of B. So at 1.0 A is four times the chance of B, at 2.0 16 times, at 0.5 sqrt(4) = 2 times and at 0.0 both have equal weights.", new AcceptableValueRange<float>(0f, 2f));
			CheapMoonBiasIgnorePriceChanges = GetConfigValue("6.1 - Cheap Moon Bias", "Ignore price changes", defaultValue: true, "Ignore any changes to moon prices by discounts or sales and only consider original price for biased selections.");
			MoonGroupMatchingMethod = _configFile.Bind<string>("6.2 - Moon Group Matching", "Group Matching Method", "Price", new ConfigDescription("The method used to group moons. Group Matching can be used to limit some discoveries to moons of the same group.\n'Price': All moons of the same price are considered a group. This method ignores price changes by unlocks, discounts, or sales.\n'PriceRange': All moons within a set price range are considered a group. Upper and lower range is defined by the price range setting below.\n'PriceRangeUpper': All moons within a set upper price range are considered a group. Upper range is defined by the price range setting below.\n'Tag': All moons that have at least one tag in common are considered a group.\n'LethalConstellations': Match moons to their constellations as they are configured in LethalConstellations. See settings in Advanced section.'Custom': Define custom named groups of moons below.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[6] { "Price", "PriceRange", "PriceRangeUpper", "Tag", "LethalConstellations", "Custom" }), Array.Empty<object>())).Value;
			MoonGroupMatchingPriceRange = GetConfigValue("6.2 - Moon Group Matching", "Price range", 200, "The price range used for matching moons via 'PriceRange' and 'PriceRangeUpper' methods.\nIt will match all moons priced within the original price +- this value (+ this value for upper range).");
			MoonGroupMatchingCustom = GetConfigValue("6.2 - Moon Group Matching", "Custom moon groups", "", "Define your own custom moon groups.\nExpected Format: Separate moon groups by \"|\" and moons by \",\".\nExample: 'Group name 1: Experimentation, Assurance, Vow | Group name 2: Offense, March, Adamance'\nNames must be exact matches. The option below can be used to get the names.");
			MoonGroupMatchingCustomDict = ParseCustomMoonGroups();
			MoonGroupMatchingCustomHelper = GetConfigValue("6.2 - Moon Group Matching", "Print moon names to console", defaultValue: false, "Print the names you need to define your custom groups to console/log. They will be logged after you've loaded into a save game.");
			TerminalTagLineWidth = GetConfigValue("6.3 - Terminal", "Maximum tag line length", 49, "By default LMU tries to fit as many tags as possible into a single line.\nDecrease this value if you want to have a more organized look at the cost of more scrolling depending on the amount of tags you see.\nNOTE: Don't worry about setting it too low. It will always put at least one tag per line. Only if any additional tag would exceed this value it puts a line break.\nDo not set it larger than default unless you are also decreasing font size below.", new AcceptableValueRange<int>(10, 100));
			TerminalFontSizeOverride = GetConfigValue("6.3 - Terminal", "Override Terminal font size", defaultValue: true, "Override the font size in the Terminal's moon catalogue.\nPrevents inconsistencies with formatting. Disable to let LLL dynamically size the font depending on the number of moons visible\nNOTE: With very few moons you might see some ugly line breaks with custom weathers with long names (Meteor Shower).");
			TerminalFontSize = GetConfigValue("6.3 - Terminal", "Terminal font size", 15f, "Customize the Terminal's moon catalogue font size.\nNOTE: When using smaller fonts you can increase the maximum tag line width above.", new AcceptableValueRange<float>(8f, 15f));
			TerminalScrollAmount = GetConfigValue("6.3 - Terminal", "Terminal scroll amount", 0, "Override the Terminal's moon catalogue scroll amount. Lines per scroll action. 0 to disable\nNOTE: This can help when you have so many moons that some are skipped when scrolling.", new AcceptableValueRange<int>(0, 20));
			AlertMessageQueueing = GetConfigValue("6.4 - Compatibility", "Avoid alert messages overlapping", defaultValue: true, "When enabled, LethalMoonUnlocks will intercept all alert messages (yellow/red pop-up) and add them to a queue. This avoids alert messages from other mods and Vanilla from overlapping or not showing at all. Disable if you experience issues.");
			PreferLQRisk = GetConfigValue("6.4 - Compatibility", "Prefer LethalQuantities risk level", defaultValue: false, "Show the moon risk levels set by LethalQuantities in the moon catalogue instead of the default risk levels.");
			MalfunctionsNavigation = GetConfigValue("6.4 - Compatibility", "Malfunctions navigation buys moon", defaultValue: false, "When the Malfunctions navigation malfunction is triggered LMU will interpret it as if the moon routed to was bought.");
			LethalConstellationsOverridePrice = GetConfigValue("6.4 - Compatibility", "LethalConstellations override price", defaultValue: false, "When enabled and LethalConstellations is present override the constellation routing price with the default moon's routing price.\nRouting to the constellation will be considered buying the default moon. Consequently unlocks, discounts and sales of the default moon will be granted and will also apply to the constellation routing price.\nNOTE: In Discovery Mode the default moon will always be set to the cheapest currently discovered moon of that constellation regardless of this setting.");
		}

		private static T GetConfigValue<T>(string section, string key, T defaultValue, string description)
		{
			return _configFile.Bind<T>(section, key, defaultValue, description).Value;
		}

		private static T GetConfigValue<T>(string section, string key, T defaultValue, string description, AcceptableValueRange<int> range)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			return _configFile.Bind<T>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)range, Array.Empty<object>())).Value;
		}

		private static T GetConfigValue<T>(string section, string key, T defaultValue, string description, AcceptableValueRange<float> range)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			return _configFile.Bind<T>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)(object)range, Array.Empty<object>())).Value;
		}

		private static void EnsureConfigExists()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			if (_configFile == null)
			{
				_configFile = new ConfigFile(_configPath, true);
			}
		}
	}
	internal readonly struct LMGroup
	{
		public string Name { get; init; }

		public List<LMUnlockable> Members { get; init; }

		public LMGroup()
		{
			Name = string.Empty;
			Members = new List<LMUnlockable>();
		}
	}
	[Serializable]
	[ES3Serializable]
	internal class LMUnlockable
	{
		[NonSerialized]
		[ES3NonSerializable]
		internal ExtendedLevel ExtendedLevel;

		[SerializeField]
		[ES3Serializable]
		internal string Name { get; private set; }

		public int OriginalPrice { get; private set; }

		public bool OriginallyHidden { get; private set; }

		public bool OriginallyLocked { get; private set; }

		[SerializeField]
		[ES3Serializable]
		internal int BuyCount { get; set; }

		[SerializeField]
		[ES3Serializable]
		internal int VisitCount { get; set; }

		[SerializeField]
		[ES3Serializable]
		internal int FreeVisitCount { get; set; }

		[SerializeField]
		[ES3Serializable]
		internal int LandingCount { get; set; }

		[SerializeField]
		[ES3Serializable]
		internal bool Discovered { get; set; }

		[SerializeField]
		[ES3Serializable]
		internal bool NewDiscovery { get; set; }

		[SerializeField]
		[ES3Serializable]
		internal bool DiscoveredOnce { get; set; }

		[SerializeField]
		[ES3Serializable]
		internal bool PermanentlyDiscovered { get; set; }

		[SerializeField]
		[ES3Serializable]
		internal bool OnSale { get; set; }

		[SerializeField]
		[ES3Serializable]
		internal int SalesRate { get; set; }

		public LMUnlockable(string name, int originalPrice, bool originallyHidden, bool originallyLocked)
		{
			Name = name;
			ExtendedLevel = UnlockManager.Instance.AllLevels.Where((ExtendedLevel level) => level.NumberlessPlanetName == Name).FirstOrDefault();
			OriginalPrice = originalPrice;
			OriginallyHidden = originallyHidden;
			OriginallyLocked = originallyLocked;
		}

		public void OverrideData(LMUnlockable newData)
		{
			if (Name != newData.Name)
			{
				Plugin.Instance.Mls.LogError((object)"Name mismatch during override LMUnlockable data!");
				return;
			}
			BuyCount = newData.BuyCount;
			VisitCount = newData.VisitCount;
			FreeVisitCount = newData.FreeVisitCount;
			LandingCount = newData.LandingCount;
			Discovered = newData.Discovered;
			NewDiscovery = newData.NewDiscovery;
			DiscoveredOnce = newData.DiscoveredOnce;
			PermanentlyDiscovered = newData.PermanentlyDiscovered;
			OnSale = newData.OnSale;
			SalesRate = newData.SalesRate;
		}

		public void ApplyPrice()
		{
			int num = OriginalPrice;
			if (BuyCount > 0)
			{
				if (ConfigManager.DiscountMode)
				{
					num = (int)((float)num * Plugin.GetDiscountRate(BuyCount));
					Plugin.Instance.Mls.LogDebug((object)$"{Name}: Discount applied ({num})");
				}
				else if (ConfigManager.UnlockMode)
				{
					num = 0;
					Plugin.Instance.Mls.LogDebug((object)$"{Name}: Unlock applied ({num})");
				}
			}
			if (OnSale && num > 0)
			{
				num = (int)((float)(num * (100 - SalesRate)) / 100f);
				Plugin.Instance.Mls.LogDebug((object)$"{Name}: Sales rate applied ({num})");
			}
			ExtendedLevel.RoutePrice = num;
		}

		public void ApplyDiscoverability()
		{
			if (!ConfigManager.DiscoveryMode)
			{
				if (OriginallyHidden)
				{
					ExtendedLevel.IsRouteHidden = true;
				}
				else
				{
					ExtendedLevel.IsRouteHidden = false;
				}
				if (OriginallyLocked)
				{
					ExtendedLevel.IsRouteLocked = true;
				}
				else
				{
					ExtendedLevel.IsRouteLocked = false;
				}
				return;
			}
			if (BuyCount > 0 && !PermanentlyDiscovered && ((ConfigManager.UnlockMode && !ConfigManager.DiscountMode && ConfigManager.DiscoveryKeepUnlocks) || (ConfigManager.DiscountMode && ConfigManager.DiscoveryKeepDiscounts)))
			{
				PermanentlyDiscovered = true;
				Plugin.Instance.Mls.LogInfo((object)(Name + " set to permanently discovered because it's " + (ConfigManager.DiscoveryKeepUnlocks ? "unlocked" : "discounted.")));
			}
			if (Discovered && !OriginallyHidden && !OriginallyLocked && OriginalPrice == 0 && ConfigManager.PermanentlyDiscoverFreeMoonsOnLanding > -1 && LandingCount >= ConfigManager.PermanentlyDiscoverFreeMoonsOnLanding)
			{
				PermanentlyDiscovered = true;
			}
			if (Discovered && !OriginallyHidden && !OriginallyLocked && OriginalPrice > 0 && ConfigManager.PermanentlyDiscoverPaidMoonsOnLanding > -1 && LandingCount >= ConfigManager.PermanentlyDiscoverPaidMoonsOnLanding)
			{
				PermanentlyDiscovered = true;
			}
			if (OriginallyHidden)
			{
				Discovered = false;
				if (ConfigManager.PermanentlyDiscoverHiddenMoonsOnVisit && VisitCount > 0)
				{
					PermanentlyDiscovered = true;
					ExtendedLevel.IsRouteHidden = false;
				}
				else
				{
					PermanentlyDiscovered = false;
					ExtendedLevel.IsRouteHidden = true;
				}
			}
			if (OriginallyLocked)
			{
				Discovered = false;
				PermanentlyDiscovered = false;
				ExtendedLevel.IsRouteHidden = true;
				ExtendedLevel.IsRouteLocked = true;
			}
			if (Discovered || PermanentlyDiscovered)
			{
				if (!DiscoveredOnce)
				{
					NewDiscovery = true;
					DiscoveredOnce = true;
				}
				ExtendedLevel.IsRouteHidden = false;
				ExtendedLevel.IsRouteLocked = false;
				Plugin.Instance.Mls.LogDebug((object)(Name + " is visible in terminal moon catalogue"));
			}
			else if (!Discovered && !PermanentlyDiscovered && !OriginallyHidden && !OriginallyLocked)
			{
				ExtendedLevel.IsRouteHidden = true;
				ExtendedLevel.IsRouteLocked = true;
			}
		}

		public void RestoreOriginalState()
		{
			ExtendedLevel.RoutePrice = OriginalPrice;
			ExtendedLevel.IsRouteHidden = OriginallyHidden;
			ExtendedLevel.IsRouteLocked = OriginallyLocked;
		}

		public void RefreshSale()
		{
			if (Random.Range(0, 100) < ConfigManager.SalesChance && ExtendedLevel.RoutePrice > 0)
			{
				OnSale = true;
				SalesRate = ConfigManager.SalesRate;
				Plugin.Instance.Mls.LogDebug((object)$"{Name} is on SALE for {SalesRate}% OFF!");
			}
			else
			{
				OnSale = false;
				SalesRate = 0;
			}
		}

		public void VisitMoon()
		{
			VisitCount++;
			Plugin.Instance.Mls.LogDebug((object)$"{Name}: Set visit count to {VisitCount}");
			if ((ExtendedLevel.RoutePrice == 0 || (ConfigManager.DiscountMode && BuyCount == ConfigManager.DiscountsCount)) && OriginalPrice != ExtendedLevel.RoutePrice)
			{
				FreeVisitCount++;
				Plugin.Instance.Mls.LogDebug((object)$"{Name}: Set free visit count to {FreeVisitCount}");
				if (ConfigManager.UnlockMode && !ConfigManager.DiscountMode && ConfigManager.UnlocksResetAfterVisits > 0)
				{
					if (FreeVisitCount > ConfigManager.UnlocksResetAfterVisits)
					{
						Plugin.Instance.Mls.LogInfo((object)$"{Name}: Reset unlock due to free visit count ({FreeVisitCount - 1}) reached.");
						NotificationHelper.SendChatMessage("Unlock expired:\n<color=red>" + Name + "</color>");
						NetworkManager.Instance.ServerSendAlertMessage(new Notification
						{
							Header = "Unlock expired!",
							Text = "Your unlock for " + Name + " has been used " + (FreeVisitCount - 1).NumberOfWords("time") + " and expired.",
							IsWarning = true,
							Key = "LMU_UnlockExpired"
						});
						BuyCount = 0;
						FreeVisitCount = 0;
						if (ConfigManager.UnlocksResetAfterVisitsPermDiscovery)
						{
							Plugin.Instance.Mls.LogInfo((object)(Name + ": Also resetting permanent discovery status."));
							PermanentlyDiscovered = false;
						}
					}
					else if (FreeVisitCount > 1)
					{
						NetworkManager.Instance.ServerSendAlertMessage(new Notification
						{
							Header = "Unlock: " + Name,
							Text = "Unlock used! " + (FreeVisitCount - 1).CountToText() + " use.\nYou have " + (ConfigManager.UnlocksResetAfterVisits - FreeVisitCount + 1).NumberOfWords("use") + " left.",
							Key = "LMU_UnlockUsed"
						});
					}
				}
				if (ConfigManager.DiscountMode && ConfigManager.DiscountsResetAfterVisits > 0)
				{
					if (FreeVisitCount > ConfigManager.DiscountsResetAfterVisits)
					{
						Plugin.Instance.Mls.LogInfo((object)$"{Name}: Reset discount due to free visit count ({FreeVisitCount - 1}) reached.");
						NotificationHelper.SendChatMessage("Discount expired:\n<color=red>" + Name + "</color>");
						NetworkManager.Instance.ServerSendAlertMessage(new Notification
						{
							Header = "Discount expired!",
							Text = "Your discount for " + Name + " has been used " + (FreeVisitCount - 1).NumberOfWords("time") + " and expired.",
							IsWarning = true,
							Key = "LMU_DiscountExpired"
						});
						BuyCount = 0;
						FreeVisitCount = 0;
						if (ConfigManager.DiscountsResetAfterVisitsPermDiscovery)
						{
							Plugin.Instance.Mls.LogInfo((object)(Name + ": Also resetting permanent discovery status."));
							PermanentlyDiscovered = false;
						}
					}
					else if (FreeVisitCount > 1)
					{
						NetworkManager.Instance.ServerSendAlertMessage(new Notification
						{
							Header = "Discount: " + Name,
							Text = "Discount redeemed! " + (FreeVisitCount - 1).CountToText() + " use.\nYou have " + (ConfigManager.DiscountsResetAfterVisits - FreeVisitCount + 1).NumberOfWords("use") + " left.",
							Key = "LMU_DiscountUsed"
						});
					}
				}
			}
			DelayHelper.Instance.ExecuteAfterDelay(NetworkManager.Instance.ServerSendAlertQueueEvent, 1f);
		}

		public void Land()
		{
			LandingCount++;
		}

		public Dictionary<string, List<string>> GetMatchingCustomGroups()
		{
			Dictionary<string, List<string>> moonGroupMatchingCustomDict = ConfigManager.MoonGroupMatchingCustomDict;
			Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();
			foreach (KeyValuePair<string, List<string>> item in moonGroupMatchingCustomDict)
			{
				if (item.Value.Contains(Name))
				{
					dictionary.Add(item.Key, item.Value);
				}
			}
			return dictionary;
		}

		public string GetMoonPreviewText(PreviewInfoType infoType)
		{
			int num = Name.Count();
			string format = "{0, -" + Math.Clamp(18 - num, 0, 18) + "} {1, -7} {2, -9} {3, -13}";
			string text = string.Empty;
			string empty = string.Empty;
			string empty2 = string.Empty;
			empty2 = ((!Plugin.WeatherTweaksPresent) ? ((object)(LevelWeatherType)(ref ExtendedLevel.SelectableLevel.currentWeather)).ToString() : WTCompatibility.GetWeatherTweaksWeather(this));
			if (empty2.Trim().Equals("None"))
			{
				empty2 = string.Empty;
			}
			string text2 = string.Empty;
			if (Plugin.LQPresent && ConfigManager.PreferLQRisk)
			{
				text2 = LQCompatibility.GetLQRiskLevel(this);
			}
			if (string.IsNullOrEmpty(text2))
			{
				text2 = ExtendedLevel.SelectableLevel.riskLevel;
			}
			if (text2.Count() > 7)
			{
				text2 = text2.Substring(0, 5) + "..";
			}
			if (((object)(PreviewInfoType)(ref infoType)).Equals((object)(PreviewInfoType)2))
			{
				text = string.Format(format, empty, empty, "$" + ExtendedLevel.RoutePrice, empty2);
			}
			else if (((object)(PreviewInfoType)(ref infoType)).Equals((object)(PreviewInfoType)0))
			{
				text = string.Format(format, empty, empty, "$" + ExtendedLevel.RoutePrice, empty);
			}
			else if (((object)(PreviewInfoType)(ref infoType)).Equals((object)(PreviewInfoType)1))
			{
				text = string.Format(format, empty, text2, empty, empty);
			}
			else if (((object)(PreviewInfoType)(ref infoType)).Equals((object)(PreviewInfoType)3))
			{
				text = string.Format(format, empty, empty, empty, empty);
			}
			else if (((object)(PreviewInfoType)(ref infoType)).Equals((object)(PreviewInfoType)4))
			{
				text = string.Format(format, empty, text2, "$" + ExtendedLevel.RoutePrice, empty2);
			}
			else if (((object)(PreviewInfoType)(ref infoType)).Equals((object)(PreviewInfoType)6))
			{
				text = string.Format(format, empty, empty, empty, empty);
			}
			else if (((object)(PreviewInfoType)(ref infoType)).Equals((object)(PreviewInfoType)7))
			{
				text = string.Format(format, empty, empty, empty, empty);
			}
			if (ExtendedLevel.IsRouteLocked)
			{
				text += "\n  * (Locked)";
			}
			if (!ConfigManager.DisplayTerminalTags)
			{
				return text;
			}
			string text3 = string.Empty;
			if ((Object)(object)ExtendedLevel == (Object)(object)LevelManager.CurrentExtendedLevel && ConfigManager.ShowTagInOrbit)
			{
				text3 = AddTagToPreviewText("[IN ORBIT]", text3);
			}
			if (NewDiscovery && ConfigManager.DiscoveryMode && ConfigManager.ShowTagNewDiscovery)
			{
				text3 = AddTagToPreviewText("[NEW]", text3);
			}
			if (LandingCount > 0 && ConfigManager.ShowTagExplored)
			{
				text3 = AddTagToPreviewText($"[EXPLORED:{LandingCount}]", text3);
			}
			else if (LandingCount == 0 && ConfigManager.ShowTagExplored)
			{
				text3 = AddTagToPreviewText("[UNEXPLORED]", text3);
			}
			if (FreeVisitCount > 0 && ConfigManager.UnlockMode && !ConfigManager.DiscountMode && ConfigManager.UnlocksResetAfterVisits > 0 && ConfigManager.ShowTagUnlockDiscount)
			{
				text3 = AddTagToPreviewText($"[UNLOCK EXPIRES:{ConfigManager.UnlocksResetAfterVisits - FreeVisitCount + 1}]", text3);
			}
			else if (FreeVisitCount > 0 && ConfigManager.DiscountMode && ConfigManager.DiscountsResetAfterVisits > 0 && ConfigManager.ShowTagUnlockDiscount)
			{
				text3 = AddTagToPreviewText($"[DISCOUNT EXPIRES:{ConfigManager.DiscountsResetAfterVisits - FreeVisitCount + 1}]", text3);
			}
			else if (ConfigManager.UnlockMode && !ConfigManager.DiscountMode && BuyCount > 0 && ConfigManager.ShowTagUnlockDiscount)
			{
				text3 = AddTagToPreviewText("[UNLOCKED]", text3);
			}
			else if (ConfigManager.DiscountMode && BuyCount > 0 && ConfigManager.ShowTagUnlockDiscount)
			{
				int num2 = 100 - (int)(Plugin.GetDiscountRate(BuyCount) * 100f);
				text3 = ((num2 == 100) ? AddTagToPreviewText("[FULL DISCOUNT]", text3) : AddTagToPreviewText($"[DISCOUNT-{num2}%]", text3));
			}
			if (PermanentlyDiscovered && !ConfigManager.DiscoveryNeverShuffle && ConfigManager.DiscoveryMode && ConfigManager.ShowTagPermanentDiscovery && ((OriginalPrice == 0 && ConfigManager.PermanentlyDiscoverFreeMoonsOnLanding != 0) || (OriginalPrice > 0 && ConfigManager.PermanentlyDiscoverPaidMoonsOnLanding != 0)))
			{
				text3 = AddTagToPreviewText("[PINNED]", text3);
			}
			if (OnSale && SalesRate > 0 && ExtendedLevel.RoutePrice > 0 && ConfigManager.Sales && ConfigManager.ShowTagSale)
			{
				text3 = AddTagToPreviewText($"[SALE-{SalesRate}%]", text3);
			}
			Dictionary<string, List<string>> matchingCustomGroups = GetMatchingCustomGroups();
			if (ConfigManager.MoonGroupMatchingMethod == "Custom" && matchingCustomGroups.Count > 0 && ConfigManager.ShowTagGroups)
			{
				string text4 = string.Empty;
				if (matchingCustomGroups.Count > 1)
				{
					text4 = string.Join("/", matchingCustomGroups.Keys);
				}
				else if (matchingCustomGroups.Count == 1)
				{
					text4 = matchingCustomGroups.Keys.First();
				}
				text3 = AddTagToPreviewText("[" + text4.Trim().ToUpper() + "]", text3);
			}
			else if (Plugin.LethalConstellationsPresent && Plugin.LethalConstellationsExtension != null && ConfigManager.MoonGroupMatchingMethod == "LethalConstellations" && ConfigManager.ShowTagGroups)
			{
				text3 = AddTagToPreviewText("[" + Plugin.LethalConstellationsExtension.GetConstellationName(this).ToUpper() + "]", text3);
			}
			else if (ConfigManager.MoonGroupMatchingMethod == "Tag")
			{
				List<ContentTag> contentTags = ((ExtendedContent)ExtendedLevel).ContentTags;
				string text5 = string.Empty;
				if (contentTags.Count > 1)
				{
					text5 = string.Join("/", contentTags.Select((ContentTag tag) => tag.contentTagName.ToUpper()));
				}
				else if (contentTags.Count == 1)
				{
					text5 = ((object)contentTags.FirstOrDefault()).ToString();
				}
				if (!string.IsNullOrEmpty(text5))
				{
					text3 = AddTagToPreviewText("[" + text5 + "]", text3);
				}
			}
			if (!string.IsNullOrEmpty(text3))
			{
				text += text3;
			}
			if (ConfigManager.TerminalFontSizeOverride)
			{
				UnlockManager.Instance.Terminal.screenText.textComponent.fontSize = ConfigManager.TerminalFontSize;
			}
			return text;
		}

		private string AddTagToPreviewText(string newTag, string previewText)
		{
			if (previewText == string.Empty)
			{
				previewText = "\n  *";
			}
			string[] array = previewText.Split('\n', StringSplitOptions.RemoveEmptyEntries);
			previewText = ((array[^1].Length + newTag.Length >= ConfigManager.TerminalTagLineWidth && !(array[^1] == "  *")) ? (previewText + "\n  * " + newTag) : (previewText + " " + newTag));
			return previewText;
		}

		public override string ToString()
		{
			string text = "";
			if (OriginallyHidden && !OriginallyLocked)
			{
				text = "LLL_H";
			}
			else if (OriginallyLocked && !OriginallyHidden)
			{
				text = "LLL_L";
			}
			else if (OriginallyHidden && OriginallyLocked)
			{
				text = "LLL_HL";
			}
			return string.Format(UnlockManager.LogFormatString, Name, BuyCount, VisitCount, FreeVisitCount, Discovered, NewDiscovery, DiscoveredOnce, PermanentlyDiscovered, OnSale, SalesRate, OriginalPrice, text);
		}
	}
	internal class NetworkManager
	{
		private static LNetworkMessage<List<LMUnlockable>> UnlockablesMessage;

		private static LNetworkMessage<string> BuyMoonMessage;

		private static LNetworkEvent RequestSyncEvent;

		private static LNetworkMessage<Notification> AlertMessage;

		private static LNetworkEvent SendAlertQueueEvent;

		public static NetworkManager Instance { get; private set; }

		public NetworkManager()
		{
			if (Instance == null)
			{
				Instance = this;
			}
			Plugin.Instance.Mls.LogInfo((object)"Register Network messages..");
			UnlockablesMessage = LNetworkMessage<List<LMUnlockable>>.Connect("LMU_Unlocks", (Action<List<LMUnlockable>, ulong>)null, (Action<List<LMUnlockable>>)ClientReceiveUnlockables, (Action<List<LMUnlockable>, ulong>)null);
			BuyMoonMessage = LNetworkMessage<string>.Connect("LMU_BuyMoonMessage", (Action<string, ulong>)ServerReceiveBuyMoon, (Action<string>)null, (Action<string, ulong>)null);
			RequestSyncEvent = LNetworkEvent.Connect("LMU_RequestSyncEvent", (Action<ulong>)ServerReceiveRequestSyncEvent, (Action)null, (Action<ulong>)null);
			AlertMessage = LNetworkMessage<Notification>.Connect("LMU_AlertMessage", (Action<Notification, ulong>)null, (Action<Notification>)ClientReceiveAlertMessage, (Action<Notification, ulong>)null);
			SendAlertQueueEvent = LNetworkEvent.Connect("LMU_SendAlertQueueEvent", (Action<ulong>)null, (Action)ClientReceiveSendAlertQueueEvent, (Action<ulong>)null);
			Plugin.Instance.Mls.LogInfo((object)"NetworkManager created.");
		}

		internal bool IsServer()
		{
			return NetworkManager.Singleton.IsServer;
		}

		internal void ServerSendUnlockables(List<LMUnlockable> unlockables, ulong client_id = 0uL)
		{
			if (IsServer())
			{
				if (client_id != 0)
				{
					Plugin.Instance.Mls.LogInfo((object)$"Syncing unlockables to client with id {client_id}");
				}
				else
				{
					Plugin.Instance.Mls.LogInfo((object)"Syncing unlockables to all clients..");
				}
				if (client_id != 0)
				{
					UnlockablesMessage.SendClient(unlockables, client_id);
				}
				else
				{
					UnlockablesMessage.SendClients(unlockables);
				}
			}
		}

		internal void ServerSendAlertMessage(Notification alert)
		{
			if (IsServer())
			{
				AlertMessage.SendClients(alert);
			}
		}

		internal void ServerSendAlertQueueEvent()
		{
			if (IsServer())
			{
				SendAlertQueueEvent.InvokeClients();
			}
		}

		internal void ClientBuyMoon(string moon)
		{
			if (!IsServer())
			{
				Plugin.Instance.Mls.LogInfo((object)"Sending buy message to host..");
				BuyMoonMessage.SendServer(moon);
			}
		}

		internal void ClientRequestSync()
		{
			if (!IsServer())
			{
				Plugin.Instance.Mls.LogInfo((object)"Requesting sync from host..");
				RequestSyncEvent.InvokeServer();
			}
		}

		private void ClientReceiveUnlockables(List<LMUnlockable> payload)
		{
			if (!IsServer())
			{
				Plugin.Instance.Mls.LogInfo((object)"Receiving LMU data..");
				UnlockManager.Instance.ImportUnlockableData(payload);
			}
			UnlockManager.Instance.ApplyUnlocks();
		}

		private void ClientReceiveAlertMessage(Notification alert)
		{
			if (ConfigManager.ShowAlerts)
			{
				Plugin.Instance.Mls.LogDebug((object)"Receiving alert message..");
				NotificationHelper.AddNotificationToQueue(alert);
			}
		}

		private void ClientReceiveSendAlertQueueEvent()
		{
			if (ConfigManager.ShowAlerts)
			{
				((MonoBehaviour)DelayHelper.Instance).StartCoroutine(NotificationHelper.SendQueuedNotifications());
			}
		}

		private void ServerReceiveBuyMoon(string moon, ulong id)
		{
			if (IsServer())
			{
				Plugin.Instance.Mls.LogInfo((object)$"Received buy message for moon {moon} from client with id {id}.");
				UnlockManager.Instance.BuyMoon(moon);
			}
		}

		private void ServerReceiveRequestSyncEvent(ulong client_id)
		{
			Plugin.Instance.Mls.LogInfo((object)$"Received sync request from client with id {client_id}..");
			ServerSendUnlockables(UnlockManager.Instance.Unlocks, client_id);
		}
	}
	[BepInPlugin("com.xmods.lethalmoonunlocks", "LethalMoonUnlocks", "2.1.9")]
	[BepInDependency("imabatby.lethallevelloader", "1.3.10")]
	[BepInDependency("LethalNetworkAPI", "3.2.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private readonly Harmony _harmony = new Harmony("LethalMoonUnlocks");

		internal static bool LQPresent;

		internal static bool LethalConstellationsPresent;

		internal static bool WeatherTweaksPresent;

		internal ManualLogSource Mls;

		private bool _loaded;

		internal static Plugin Instance { get; private set; }

		internal static LethalConstellationsExtension LethalConstellationsExtension { get; private set; }

		internal NetworkManager NetworkManager { get; private set; }

		internal UnlockManager UnlockManager { get; private set; }

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			_harmony.PatchAll(typeof(GameNetworkManagerPatch));
			_harmony.PatchAll(typeof(RoundManagerPatch));
			_harmony.PatchAll(typeof(StartOfRoundPatch));
			_harmony.PatchAll(typeof(TerminalPatch));
			_harmony.PatchAll(typeof(TimeOfDayPatch));
			_harmony.PatchAll(typeof(HUDManagerPatch));
			Mls = Logger.CreateLogSource("LethalMoonUnlocks");
			if (!_loaded)
			{
				Initialize();
			}
		}

		public void Start()
		{
			if (!_loaded)
			{
				Initialize();
			}
		}

		public void OnDestroy()
		{
			if (!_loaded)
			{
				Initialize();
			}
		}

		public void Initialize()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("DelayHelper");
			Object.DontDestroyOnLoad((Object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<DelayHelper>();
			SceneManager.sceneUnloaded += AfterGameInit;
			Mls.LogInfo((object)"LethalMoonUnlocks 2.1.9 initialized!");
			_loaded = true;
		}

		private void AfterGameInit(Scene scene)
		{
			if (!(((Scene)(ref scene)).name != "InitScene") || !(((Scene)(ref scene)).name != "InitSceneLANMode"))
			{
				Mls.LogInfo((object)"Checking for compatible mods..");
				if (Chainloader.PluginInfos.ContainsKey("LethalQuantities"))
				{
					Mls.LogInfo((object)"Lethal Quantities found! Enabling compatibility..");
					LQPresent = true;
				}
				if (Chainloader.PluginInfos.ContainsKey("com.zealsprince.malfunctions"))
				{
					Mls.LogInfo((object)"Malfunctions found! Enabling compatibility..");
					_harmony.PatchAll(typeof(MalfunctionsCompatibility));
				}
				if (Chainloader.PluginInfos.ContainsKey("com.github.darmuh.LethalConstellations"))
				{
					Mls.LogInfo((object)"LethalConstellations found! Enabling compatibility..");
					LethalConstellationsPresent = true;
					LethalConstellationsExtension = new LethalConstellationsExtension();
				}
				if (Chainloader.PluginInfos.ContainsKey("WeatherTweaks"))
				{
					Mls.LogInfo((object)"WeatherTweaks found! Enabling compatibility..");
					WeatherTweaksPresent = true;
					_harmony.PatchAll(typeof(WTCompatibility));
				}
				ConfigManager.RefreshConfig();
				if (ConfigManager.TerminalScrollAmount > 0)
				{
					Mls.LogInfo((object)"TerminalScrollAmount is set to a positive value! Patching scroll amount..");
					_harmony.PatchAll(typeof(PlayerControllerBPatch));
				}
				NetworkManager = new NetworkManager();
				UnlockManager = new UnlockManager();
				SceneManager.sceneUnloaded -= AfterGameInit;
			}
		}

		public static float GetDiscountRate(int discount_number)
		{
			List<int> list = new List<int>();
			foreach (int discount in ConfigManager.Discounts)
			{
				list.Add(100 - Mathf.Clamp(discount, 0, 100));
			}
			if (discount_number > list.Count)
			{
				discount_number = list.Count;
			}
			return (float)list[discount_number - 1] / 100f;
		}
	}
	internal static class RandomSelector
	{
		public static List<T> Get<T>(List<T> objects, int amount)
		{
			if (objects.Count < amount || objects.Count == 0 || objects == null)
			{
				return objects;
			}
			List<T> list = new List<T>(objects);
			List<T> list2 = new List<T>();
			while (list2.Count < amount)
			{
				list2.Add(list[Random.Range(0, list.Count)]);
				list.Remove(list2.Last());
			}
			CheckResult(list2, amount);
			return list2;
		}

		public static List<T> GetWeighted<T>(Dictionary<T, int> objects, int amount)
		{
			if (objects.Count < amount || objects.Count == 0 || objects == null)
			{
				return new List<T>(objects.Keys);
			}
			Dictionary<T, int> dictionary = new Dictionary<T, int>(objects);
			List<T> list = new List<T>();
			while (list.Count < amount)
			{
				int num = dictionary.Sum((KeyValuePair<T, int> entry) => entry.Value);
				int num2 = Random.Range(0, num);
				T val = default(T);
				foreach (KeyValuePair<T, int> item in dictionary)
				{
					if (item.Value != 0)
					{
						if (num2 < item.Value)
						{
							val = item.Key;
							break;
						}
						num2 -= item.Value;
					}
				}
				if (val == null)
				{
					break;
				}
				list.Add(val);
				dictionary.Remove(val);
			}
			CheckResult(list, amount);
			return list;
		}

		public static Dictionary<LMUnlockable, int> CalculateBiasedWeights(List<LMUnlockable> unlocks, float bias)
		{
			Dictionary<LMUnlockable, int> dictionary = new Dictionary<LMUnlockable, int>();
			if (unlocks.Count < 1)
			{
				return dictionary;
			}
			int num = unlocks.Sum((LMUnlockable unlock) => unlock.OriginalPrice);
			foreach (LMUnlockable unlock in unlocks)
			{
				int num2 = ((!ConfigManager.CheapMoonBiasIgnorePriceChanges) ? Math.Clamp(unlock.ExtendedLevel.RoutePrice, 1, int.MaxValue) : Math.Clamp(unlock.OriginalPrice, 1, int.MaxValue));
				long num3 = Math.Clamp((long)Math.Pow((float)(num / num2) * bias, bias), 1L, int.MaxValue / (unlocks.Count + 1));
				dictionary[unlock] = (int)num3;
			}
			Plugin.Instance.Mls.LogDebug((object)("Cheap moon bias: Assigned the following weights: [ " + string.Join(", ", dictionary.Select((KeyValuePair<LMUnlockable, int> weight) => weight.Key.Name + ":" + weight.Value)) + " ]"));
			return dictionary;
		}

		private static bool CheckResult<T>(List<T> result, int goal)
		{
			if (result.Count < goal)
			{
				Plugin.Instance.Mls.LogWarning((object)"Couldn't select the desired amount of elements!");
				return false;
			}
			return true;
		}
	}
	public static class SaveManager
	{
		public static Dictionary<string, object> Savedata => Load();

		private static Dictionary<string, object> Load()
		{
			Plugin.Instance.Mls.LogInfo((object)"Loading save data..");
			string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
			Dictionary<string, object> dictionary = new Dictionary<string, object>();
			if (ES3.KeyExists("LMU_Unlockables", currentSaveFileName))
			{
				List<LMUnlockable> list = ES3.Load<List<LMUnlockable>>("LMU_Unlockables", currentSaveFileName);
				dictionary.Add("LMU_Unlockables", list);
				Plugin.Instance.Mls.LogInfo((object)("Loading LMU_Unlockables: " + string.Join(", ", list.Select((LMUnlockable unlock) => unlock.Name))));
				if (ES3.KeyExists("LMU_QuotaCount", currentSaveFileName))
				{
					int num = ES3.Load<int>("LMU_QuotaCount", currentSaveFileName);
					dictionary.Add("LMU_QuotaCount", num);
					Plugin.Instance.Mls.LogInfo((object)$"Loading LMU_QuotaCount: {num}");
				}
				if (ES3.KeyExists("LMU_DayCount", currentSaveFileName))
				{
					int num2 = ES3.Load<int>("LMU_DayCount", currentSaveFileName);
					dictionary.Add("LMU_DayCount", num2);
					Plugin.Instance.Mls.LogInfo((object)$"Loading LMU_DayCount: {num2}");
				}
				if (ES3.KeyExists("LMU_QuotaUnlocksCount", currentSaveFileName))
				{
					int num3 = ES3.Load<int>("LMU_QuotaUnlocksCount", currentSaveFileName);
					dictionary.Add("LMU_QuotaUnlocksCount", num3);
					Plugin.Instance.Mls.LogInfo((object)$"Loading LMU_QuotaUnlocksCount: {num3}");
				}
				if (ES3.KeyExists("LMU_QuotaFullDiscountsCount", currentSaveFileName))
				{
					int num4 = ES3.Load<int>("LMU_QuotaFullDiscountsCount", currentSaveFileName);
					dictionary.Add("LMU_QuotaFullDiscountsCount", num4);
					Plugin.Instance.Mls.LogInfo((object)$"Loading LMU_QuotaFullDiscountsCount: {num4}");
				}
				return dictionary;
			}
			if (ES3.KeyExists("LMU_UnlockedMoons", currentSaveFileName))
			{
				Dictionary<string, int> dictionary2 = ES3.Load<Dictionary<string, int>>("LMU_UnlockedMoons", currentSaveFileName);
				dictionary.Add("LMU_UnlockedMoons", dictionary2);
				Plugin.Instance.Mls.LogInfo((object)("Loading deprecated LMU_UnlockedMoons: " + string.Join(", ", dictionary2)));
			}
			if (ES3.KeyExists("LMU_OriginalMoonPrices", currentSaveFileName))
			{
				Dictionary<string, int> dictionary3 = ES3.Load<Dictionary<string, int>>("LMU_OriginalMoonPrices", currentSaveFileName);
				dictionary.Add("LMU_OriginalMoonPrices", dictionary3);
				Plugin.Instance.Mls.LogInfo((object)("Loading deprecated LMU_OriginalMoonPrices: " + string.Join(", ", dictionary3)));
			}
			if (ES3.KeyExists("UnlockedMoons", currentSaveFileName))
			{
				List<string> list2 = ES3.Load<List<string>>("UnlockedMoons", currentSaveFileName);
				dictionary.Add("UnlockedMoons", list2);
				Plugin.Instance.Mls.LogInfo((object)("Loading Permanent Moons data UnlockedMoons: " + string.Join(", ", list2)));
			}
			if (ES3.KeyExists("MoonQuotaNum", currentSaveFileName))
			{
				int num5 = ES3.Load<int>("MoonQuotaNum", currentSaveFileName);
				dictionary.Add("MoonQuotaNum", num5);
				Plugin.Instance.Mls.LogInfo((object)$"Loading Permanet Moons data MoonQuotaNum: {num5}");
			}
			return dictionary;
		}

		public static void StoreSaveData()
		{
			Plugin.Instance.Mls.LogInfo((object)"Saving data..");
			string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName;
			if (UnlockManager.Instance.Unlocks.Count != 0)
			{
				ES3.Save<List<LMUnlockable>>("LMU_Unlockables", UnlockManager.Instance.Unlocks, currentSaveFileName);
				Plugin.Instance.Mls.LogInfo((object)"Saving LMU_Unlockables..");
				UnlockManager.Instance.LogUnlockables();
			}
			else if (ES3.KeyExists("LMU_Unlockables", currentSaveFileName))
			{
				ES3.DeleteKey("LMU_Unlockables", currentSaveFileName);
			}
			if (UnlockManager.Instance.QuotaCount > 0)
			{
				ES3.Save<int>("LMU_QuotaCount", UnlockManager.Instance.QuotaCount, currentSaveFileName);
				Plugin.Instance.Mls.LogInfo((object)("Saving LMU_QuotaCount: " + string.Join(", ", UnlockManager.Instance.QuotaCount)));
			}
			else if (ES3.KeyExists("LMU_QuotaCount", currentSaveFileName))
			{
				ES3.DeleteKey("LMU_QuotaCount", currentSaveFileName);
			}
			if (UnlockManager.Instance.DayCount > 0)
			{
				ES3.Save<int>("LMU_DayCount", UnlockManager.Instance.DayCount, currentSaveFileName);
				Plugin.Instance.Mls.LogInfo((object)("Saving LMU_DayCount: " + string.Join(", ", UnlockManager.Instance.DayCount)));
			}
			else if (ES3.KeyExists("LMU_DayCount", currentSaveFileName))
			{
				ES3.DeleteKey("LMU_DayCount", currentSaveFileName);
			}
			if (UnlockManager.Instance.QuotaUnlocksCount > 0)
			{
				ES3.Save<int>("LMU_QuotaUnlocksCount", UnlockManager.Instance.QuotaUnlocksCount, currentSaveFileName);
				Plugin.Instance.Mls.LogInfo((object)("Saving LMU_QuotaUnlocksCount: " + string.Join(", ", UnlockManager.Instance.QuotaUnlocksCount)));
			}
			else if (ES3.KeyExists("LMU_QuotaUnlocksCount", currentSaveFileName))
			{
				ES3.DeleteKey("LMU_QuotaUnlocksCount", currentSaveFileName);
			}
			if (UnlockManager.Instance.QuotaDiscountsCount > 0)
			{
				ES3.Save<int>("LMU_QuotaDiscountsCount", UnlockManager.Instance.QuotaDiscountsCount, currentSaveFileName);
				Plugin.Instance.Mls.LogInfo((object)("Saving LMU_QuotaDiscountsCount: " + string.Join(", ", UnlockManager.Instance.QuotaDiscountsCount)));
			}
			else if (ES3.KeyExists("LMU_QuotaDiscountsCount", currentSaveFileName))
			{
				ES3.DeleteKey("LMU_QuotaDiscountsCount", currentSaveFileName);
			}
			if (UnlockManager.Instance.QuotaFullDiscountsCount > 0)
			{
				ES3.Save<int>("LMU_QuotaFullDiscountsCount", UnlockManager.Instance.QuotaCount, currentSaveFileName);
				Plugin.Instance.Mls.LogInfo((object)("Saving LMU_QuotaFullDiscountsCount: " + string.Join(", ", UnlockManager.Instance.QuotaFullDiscountsCount)));
			}
			else if (ES3.KeyExists("LMU_QuotaFullDiscountsCount", currentSaveFileName))
			{
				ES3.DeleteKey("LMU_QuotaFullDiscountsCount", currentSaveFileName);
			}
			if (ES3.KeyExists("LMU_UnlockedMoons", currentSaveFileName))
			{
				Plugin.Instance.Mls.LogInfo((object)"Deleting deprecated save field: LMU_UnlockedMoons");
				ES3.DeleteKey("LMU_UnlockedMoons", currentSaveFileName);
			}
			if (ES3.KeyExists("LMU_OriginalMoonPrices", currentSaveFileName))
			{
				Plugin.Instance.Mls.LogInfo((object)"Deleting deprecated save field: LMU_OriginalMoonPrices");
				ES3.DeleteKey("LMU_OriginalMoonPrices", currentSaveFileName);
			}
		}
	}
	internal class UnlockManager
	{
		private int _discoveredFreeCount;

		private int _discoveredDynamicFreeCount;

		private int _discoveredPaidCount;

		internal static UnlockManager Instance { get; private set; }

		internal static string LogFormatString { get; } = "| {0, -20} | {1, 7} | {2, 7} | {3, 6} | {4, 11} | {5, 6} | {6, 6} | {7, 10} | {8, 7} | {9, 5} | {10, 8} | {11, 8} |";


		internal static List<string> LogHeader { get; } = new List<string>(12)
		{
			"LMUnlockable", "Bought", "Visits", "Free", "Discovered", "New", "Once", "Permanent", "OnSale", "Rate",
			"OGPrice", "Ignored"
		};


		internal Terminal Terminal { get; set; }

		internal List<ExtendedLevel> AllLevels { get; private set; } = PatchedContent.ExtendedLevels;


		internal List<LMUnlockable> Unlocks { get; set; } = new List<LMUnlockable>();


		internal int QuotaCount { get; set; }

		internal int DayCount { get; set; }

		internal int QuotaUnlocksCount { get; set; }

		internal int QuotaDiscountsCount { get; set; }

		internal int QuotaFullDiscountsCount { get; set; }

		internal int DiscoveredFreeCount
		{
			get
			{
				if (_discoveredFreeCount <= DiscoveryFreeCandidates.Count)
				{
					return _discoveredFreeCount;
				}
				return DiscoveryFreeCandidates.Count;
			}
			set
			{
				_discoveredFreeCount = value;
			}
		}

		internal int DiscoveredDynamicFreeCount
		{
			get
			{
				if (_discoveredDynamicFreeCount <= DiscoveryDynamicFreeCandidates.Count)
				{
					return _discoveredDynamicFreeCount;
				}
				return DiscoveryDynamicFreeCandidates.Count;
			}
			set
			{
				_discoveredDynamicFreeCount = value;
			}
		}

		internal int DiscoveredPaidCount
		{
			get
			{
				if (_discoveredPaidCount <= DiscoveryPaidCandidates.Count)
				{
					return _discoveredPaidCount;
				}
				return DiscoveryPaidCandidates.Count;
			}
			set
			{
				_discoveredPaidCount = value;
			}
		}

		internal List<LMUnlockable> FreeMoons => Unlocks.Where((LMUnlockable unlock) => unlock.OriginalPrice == 0).ToList();

		internal List<LMUnlockable> DynamicFreeMoons => Unlocks.Where((LMUnlockable unlock) => unlock.ExtendedLevel.RoutePrice == 0).ToList();

		internal List<LMUnlockable> PaidMoons => Unlocks.Where((LMUnlockable unlock) => unlock.ExtendedLevel.RoutePrice > 0).ToList();

		internal List<LMUnlockable> DiscoveryCandidates => Unlocks.Where((LMUnlockable unlock) => !unlock.OriginallyLocked && !unlock.OriginallyHidden && !unlock.Discovered && !unlock.PermanentlyDiscovered).ToList();

		internal List<LMUnlockable> DiscoveryFreeCandidates => DiscoveryCandidates.Where((LMUnlockable candidate) => candidate.OriginalPrice == 0).ToList();

		internal List<LMUnlockable> DiscoveryDynamicFreeCandidates => DiscoveryCandidates.Where((LMUnlockable candidate) => candidate.ExtendedLevel.RoutePrice == 0).ToList();

		internal List<LMUnlockable> DiscoveryPaidCandidates => DiscoveryCandidates.Where((LMUnlockable candidate) => candidate.ExtendedLevel.RoutePrice > 0).ToList();

		public UnlockManager()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			if (Instance == null)
			{
				Instance = this;
			}
			TerminalManager.onBeforePreviewInfoTextAdded += new PreviewInfoText(ReplaceTerminalPreview);
		}

		public void LogUnlockables(bool debug = true)
		{
			object[] args;
			if (debug)
			{
				ManualLogSource mls = Plugin.Instance.Mls;
				string logFormatString = LogFormatString;
				args = LogHeader.ToArray();
				mls.LogDebug((object)string.Format(logFormatString, args));
				{
					foreach (LMUnlockable unlock in Unlocks)
					{
						Plugin.Instance.Mls.LogDebug((object)unlock);
					}
					return;
				}
			}
			ManualLogSource mls2 = Plugin.Instance.Mls;
			string logFormatString2 = LogFormatString;
			args = LogHeader.ToArray();
			mls2.LogInfo((object)string.Format(logFormatString2, args));
			foreach (LMUnlockable unlock2 in Unlocks)
			{
				Plugin.Instance.Mls.LogInfo((object)unlock2);
			}
		}

		public void OnLobbyStart()
		{
			ConfigManager.RefreshConfig();
			DiscoveredFreeCount = ConfigManager.DiscoveryFreeCountBase;
			DiscoveredDynamicFreeCount = ConfigManager.DiscoveryDynamicFreeCountBase;
			DiscoveredPaidCount = ConfigManager.DiscoveryPaidCountBase;
			InitializeUnlocks();
			if (!LoadAndImportSavaData())
			{
				InitializeNewGame();
			}
			LogUnlockables();
			NetworkManager.Instance.ServerSendUnlockables(Unlocks, 0uL);
			DelayHelper.Instance.ExecuteAfterDelay(NetworkManager.Instance.ServerSendAlertQueueEvent, 2f);
		}

		public void OnNewQuota()
		{
			QuotaCount++;
			Plugin.Instance.Mls.LogInfo((object)$"New quota! Completed quota count: {QuotaCount}");
			ConfigManager.RefreshConfig();
			if (ConfigManager.DiscoveryMode)
			{
				CollectionExtensions.Do<LMUnlockable>(Unlocks.Where((LMUnlockable unlock) => unlock.NewDiscovery), (Action<LMUnlockable>)delegate(LMUnlockable unlock)
				{
					unlock.NewDiscovery = false;
				});
				if (!ConfigManager.DiscoveryNeverShuffle)
				{
					Plugin.Instance.Mls.LogInfo((object)"Shuffling moon rotation on new Quota..");
					ShuffleDiscoverable();
				}
				if (ConfigManager.QuotaDiscoveries && DiscoveryCandidates.Count > 0 && Random.Range(0, 100) < ConfigManager.QuotaDiscoveryChance)
				{
					Plugin.Instance.Mls.LogInfo((object)$"Quota Discovery triggered! (Chance: {ConfigManager.QuotaDiscoveryChance}%)");
					if (ConfigManager.QuotaDiscoveryCheapestGroup && (ConfigManager.MoonGroupMatchingMethod == "Custom" || ConfigManager.MoonGroupMatchingMethod == "LethalConstellations"))
					{
						QuotaDiscoveryGroup();
					}
					else
					{
						QuotaDiscovery();
					}
				}
			}
			if (ConfigManager.Sales)
			{
				CollectionExtensions.Do<LMUnlockable>((IEnumerable<LMUnlockable>)Unlocks, (Action<LMUnlockable>)delegate(LMUnlockable unlock)
				{
					unlock.RefreshSale();
				});
			}
			ApplyUnlocks();
			if (!ConfigManager.DiscountMode && ConfigManager.QuotaUnlocks && PaidMoons.Count > 0 && Random.Range(0, 100) < ConfigManager.QuotaUnlockChance && (ConfigManager.QuotaUnlockMaxCount < 1 || QuotaUnlocksCount < ConfigManager.QuotaUnlockMaxCount))
			{
				Plugin.Instance.Mls.LogInfo((object)$"Quota unlock triggered! (Chance: {ConfigManager.QuotaUnlockChance}%)");
				QuotaUnlock();
			}
			if (ConfigManager.DiscountMode)
			{
				if (ConfigManager.QuotaDiscounts && PaidMoons.Count > 0 && Random.Range(0, 100) < ConfigManager.QuotaDiscountChance && (ConfigManager.QuotaDiscountMaxCount < 1 || QuotaDiscountsCount < ConfigManager.QuotaDiscountMaxCount))
				{
					Plugin.Instance.Mls.LogInfo((object)$"Quota Discount triggered! (Chance: {ConfigManager.QuotaDiscountChance}%)");
					QuotaDiscount();
				}
				if (ConfigManager.QuotaFullDiscounts && PaidMoons.Count > 0 && Random.Range(0, 100) < ConfigManager.QuotaFullDiscountChance && (ConfigManager.QuotaFullDiscountMaxCount < 1 || QuotaFullDiscountsCount < ConfigManager.QuotaFullDiscountMaxCount))
				{
					Plugin.Instance.Mls.LogInfo((object)$"Quota Full Discount triggered! (Chance: {ConfigManager.QuotaFullDiscountChance}%)");
					QuotaFullDiscount();
				}
			}
			LogUnlockables(debug: false);
			NetworkManager.Instance.ServerSendUnlockables(Unlocks, 0uL);
			DelayHelper.Instance.ExecuteAfterDelay(NetworkManager.Instance.ServerSendAlertQueueEvent, 5f);
		}

		private void QuotaDiscovery()
		{
			List<LMUnlockable> discoveryCandidates = DiscoveryCandidates;
			discoveryCandidates = ((!ConfigManager.CheapMoonBiasQuotaDiscovery) ? RandomSelector.Get(discoveryCandidates, ConfigManager.QuotaDiscoveryCount) : RandomSelector.GetWeighted(RandomSelector.CalculateBiasedWeights(discoveryCandidates, ConfigManager.CheapMoonBiasQuotaDiscoveryValue), ConfigManager.QuotaDiscoveryCount));
			if (discoveryCandidates.Count == 0)
			{
				Plugin.Instance.Mls.LogInfo((object)"No moons for Quota Discovery available!");
				return;
			}
			foreach (LMUnlockable item in discoveryCandidates)
			{
				item.Discovered = true;
				if (ConfigManager.QuotaDiscoveryPermanent)
				{
					item.PermanentlyDiscovered = true;
					Plugin.Instance.Mls.LogInfo((object)("Quota Discovery is permanent: " + item.Name));
				}
			}
			NotificationHelper.SendChatMessage(discoveryCandidates.Count.SinglePluralWord("Discovery") + " granted:\n<color=white>" + string.Join(", ", discoveryCandidates.Select((LMUnlockable ndd) => ndd.Name)) + "</color>");
			NetworkManager.Instance.ServerSendAlertMessage(new Notification
			{
				Header = "New " + discoveryCandidates.Count.SinglePluralWord("Discovery") + "!",
				Text = "Received coordinates:\n" + string.Join(", ", discoveryCandidates.Select((LMUnlockable unlock) => unlock.Name)),
				Key = "LMU_NewQuotaDiscovery",
				ExceptWhenKey = "LMU_NewQuotaDiscoveryGroup"
			});
			Plugin.Instance.Mls.LogInfo((object)("New Quota Discoveries: " + string.Join(", ", discoveryCandidates.Select((LMUnlockable unlock) => unlock.Name))));
		}

		private void QuotaDiscoveryGroup()
		{
			List<LMUnlockable> discoveryCandidates = DiscoveryCandidates;
			List<LMUnlockable> list = new List<LMUnlockable>();
			LMGroup lMGroup = new LMGroup();
			if (ConfigManager.QuotaDiscoveryCheapestConstellation && ConfigManager.MoonGroupMatchingMethod == "LethalConstellations")
			{
				lMGroup = Plugin.LethalConstellationsExtension.GetCheapestUndiscoveredConstellation();
				foreach (LMUnlockable member in lMGroup.Members)
				{
					if (!member.Discovered && !member.PermanentlyDiscovered)
					{
						list.Add(member);
					}
				}
			}
			else
			{
				foreach (LMUnlockable item in discoveryCandidates.OrderBy((LMUnlockable c) => c.OriginalPrice))
				{
					Plugin.Instance.Mls.LogInfo((object)("Got cheapest candidate: " + item.Name));
					Plugin.Instance.Mls.LogInfo((object)"Checking for groups..");
					lMGroup = MatchMoonGroup(item, discoveryCandidates, fallback: false);
					if (lMGroup.Members.Count > 0)
					{
						foreach (LMUnlockable member2 in lMGroup.Members)
						{
							if (!member2.Discovered && !member2.PermanentlyDiscovered)
							{
								list.Add(member2);
							}
						}
						break;
					}
					Plugin.Instance.Mls.LogInfo((object)"Candidate has no group matches. Try next..");
				}
			}
			if (lMGroup.Members.Count <= list.Count)
			{
				NetworkManager.Instance.ServerSendAlertMessage(new Notification
				{
					Header = "Loyalty reward!",
					Text = "The company facilitates your missions. Route to: <color=red>" + lMGroup.Name + "</color> established.",
					Key = "LMU_NewQuotaDiscoveryGroup"
				});
			}
			if (list.Count < 1 && ConfigManager.QuotaDiscoveryCheapestGroupFallback)
			{
				Plugin.Instance.Mls.LogInfo((object)"Couldn't match any moons for cheapest group. Fallback to all moons..");
				list = discoveryCandidates;
				lMGroup = new LMGroup();
			}
			list = ((!ConfigManager.CheapMoonBiasQuotaDiscovery) ? RandomSelector.Get(list, ConfigManager.QuotaDiscoveryCount) : RandomSelector.GetWeighted(RandomSelector.CalculateBiasedWeights(list, ConfigManager.CheapMoonBiasQuotaDiscoveryValue), ConfigManager.QuotaDiscoveryCount));
			if (list.Count == 0)
			{
				Plugin.Instance.Mls.LogInfo((object)"No moons for Quota Discovery available!");
				return;
			}
			foreach (LMUnlockable item2 in list)
			{
				item2.Discovered = true;
				if (ConfigManager.QuotaDiscoveryPermanent)
				{
					item2.PermanentlyDiscovered = true;
					Plugin.Instance.Mls.LogInfo((object)("Quota Discovery is permanent: " + item2.Name));
				}
			}
			string text = string.Empty;
			if (lMGroup.Name != string.Empty)
			{
				text = " in <color=red>" + lMGroup.Name + "</color>";
			}
			NotificationHelper.SendChatMessage(list.Count.SinglePluralWord("Discovery") + " granted" + text + ":\n<color=white>" + string.Join(", ", list.Select((LMUnlockable qd) => qd.Name)) + "</color>");
			NetworkManager.Instance.ServerSendAlertMessage(new Notification
			{
				Header = "New " + discoveryCandidates.Count.SinglePluralWord("Discovery") + "!",
				Text = "Received coordinates:\n" + string.Join(", ", discoveryCandidates.Select((LMUnlockable unlock) => unlock.Name)),
				Key = "LMU_NewQuotaDiscovery",
				ExceptWhenKey = "LMU_NewQuotaDiscoveryGroup"
			});
			Plugin.Instance.Mls.LogInfo((object)("New Quota Discoveries: " + string.Join(", ", discoveryCandidates.Select((LMUnlockable unlock) => unlock.Name))));
		}

		private void QuotaUnlock()
		{
			List<LMUnlockable> list = PaidMoons;
			if (ConfigManager.DiscoveryMode)
			{
				list = list.Where((LMUnlockable unlock) => unlock.Discovered || unlock.PermanentlyDiscovered).ToList();
			}
			if (ConfigManager.QuotaUnlockMaxPrice > 0)
			{
				list = list.Where((LMUnlockable moon) => moon.ExtendedLevel.RoutePrice <= ConfigManager.QuotaUnlockMaxPrice).ToList();
			}
			list = ((!ConfigManager.CheapMoonBiasQuotaUnlock) ? RandomSelector.Get(list, ConfigManager.QuotaUnlockCount) : RandomSelector.GetWeighted(RandomSelector.CalculateBiasedWeights(list, ConfigManager.CheapMoonBiasQuotaUnlockValue), ConfigManager.QuotaUnlockCount));
			if (list.Count == 0)
			{
				Plugin.Instance.Mls.LogInfo((object)"No moons for Quota Unlock available!");
				return;
			}
			foreach (LMUnlockable item in list)
			{
				item.BuyCount++;
				item.FreeVisitCount = 1;
			}
			QuotaUnlocksCount++;
			if (list.Count > 1)
			{
				NotificationHelper.SendChatMessage("New moons unlocked:\n<color=green>" + string.Join(", ", list.Select((LMUnlockable unlock) => unlock.Name)) + "</color>");
			}
			else if (list.Count == 1)
			{
				NotificationHelper.SendChatMessage("New moon unlocked:\n<color=green>" + list.FirstOrDefault().Name + "</color>");
			}
			NetworkManager.Instance.ServerSendAlertMessage(new Notification
			{
				Header = list.Count.SinglePluralWord("Unlock") + " granted!",
				Text = "You earned unlocks for:\n" + string.Join(", ", list.Select((LMUnlockable unlock) => unlock.Name)),
				Key = "LMU_NewQuotaUnlock"
			});
			Plugin.Instance.Mls.LogInfo((object)("New Quota Unlocks: " + string.Join(", ", list.Select((LMUnlockable unlock) => unlock.Name))));
		}

		private void QuotaDiscount()
		{
			List<LMUnlockable> list = PaidMoons;
			if (ConfigManager.DiscoveryMode)
			{
				list = list.Where((LMUnlockable unlock) => unlock.Discovered || unlock.PermanentlyDiscovered).ToList();
			}
			if (ConfigManager.QuotaDiscountMaxPrice > 0)
			{
				list = list.Where((LMUnlockable moon) => moon.ExtendedLevel.RoutePrice <= ConfigManager.QuotaDiscountMaxPrice).ToList();
			}
			list = ((!ConfigManager.CheapMoonBiasQuotaDiscount) ? RandomSelector.Get(list, ConfigManager.QuotaDiscountCount) : RandomSelector.GetWeighted(RandomSelector.CalculateBiasedWeights(list, ConfigManager.CheapMoonBiasQuotaDiscountValue), ConfigManager.QuotaDiscountCount));
			if (list.Count == 0)
			{
				Plugin.Instance.Mls.LogInfo((object)"No moons for Quota Discount available!");
				return;
			}
			foreach (LMUnlockable item in list)
			{
				item.BuyCount++;
			}
			QuotaDiscountsCount++;
			if (list.Count == 1)
			{
				NotificationHelper.SendChatMessage("Discount granted:\n<color=green>" + list.FirstOrDefault().Name + "</color>");
			}
			else if (list.Count > 1)
			{
				NotificationHelper.SendChatMessage("Discounts granted:\n<color=green>" + string.Join(", ", list.Select((LMUnlockable unlock) => unlock.Name)) + "</color>");
			}
			NetworkManager.Instance.ServerSendAlertMessage(new Notification
			{
				Header = list.Count.SinglePluralWord("Discount") + " granted!",
				Text = "You earned discounts for:\n" + string.Join(", ", list.Select((LMUnlockable discount) => discount.Name + " " + (100 - (int)(Plugin.GetDiscountRate(discount.BuyCount) * 100f)) + "%")),
				Key = "LMU_NewQuotaDiscount"
			});
			Plugin.Instance.Mls.LogInfo((object)("New Quota Discounts: " + string.Join(", ", list.Select((LMUnlockable unlock) => unlock.Name))));
		}

		private void QuotaFullDiscount()
		{
			List<LMUnlockable> list = PaidMoons;
			if (ConfigManager.DiscoveryMode)
			{
				list = list.Where((LMUnlockable unlock) => unlock.Discovered || unlock.PermanentlyDiscovered).ToList();
			}
			if (ConfigManager.QuotaFullDiscountMaxPrice > 0)
			{
				list = list.Where((LMUnlockable moon) => moon.ExtendedLevel.RoutePrice <= ConfigManager.QuotaFullDiscountMaxPrice).ToList();
			}
			if (ConfigManager.Discounts[ConfigManager.Discounts.Count - 1] < 100)
			{
				list = list.Where((LMUnlockable unlock) => unlock.BuyCount < ConfigManager.DiscountsCount).ToList();
			}
			list = ((!ConfigManager.CheapMoonBiasQuotaFullDiscount) ? RandomSelector.Get(list, ConfigManager.QuotaFullDiscountCount) : RandomSelector.GetWeighted(RandomSelector.CalculateBiasedWeights(list, ConfigManager.CheapMoonBiasQuotaFullDiscountValue), ConfigManager.QuotaFullDiscountCount));
			if (list.Count == 0)
			{
				Plugin.Instance.Mls.LogInfo((object)"No moons for Quota Full Discount available!");
				return;
			}
			foreach (LMUnlockable item in list)
			{
				item.BuyCount = ConfigManager.DiscountsCount;
				item.FreeVisitCount = 1;
			}
			QuotaFullDiscountsCount++;
			if (list.Count == 1)
			{
				NotificationHelper.SendChatMessage("Full discount granted:\n<color=green>" + list.FirstOrDefault().Name + "</color>");
			}
			else if (list.Count > 1)
			{
				NotificationHelper.SendChatMessage("Full discounts granted:\n<color=green>" + string.Join(", ", list.Select((LMUnlockable unlock) => unlock.Name)) + "</color>");
			}
			NetworkManager.Instance.ServerSendAlertMessage(new Notification
			{
				Header = " Full " + list.Count.SinglePluralWord("Discount") + " granted!",
				Text = "You earned full discounts for:\n" + string.Join(", ", list.Select((LMUnlockable unlock) => unlock.Name)),
				Key = "LMU_NewQuotaFullDiscount"
			});
			Plugin.Instance.Mls.LogInfo((object)("New Quota Full Discounts: " + string.Join(", ", list.Select((LMUnlockable unlock) => unlock.Name))));
		}

		public void OnNewDay()
		{
			Plugin.Instance.Mls.LogDebug((object)$"DaysUntilDeadlineHUD: {(int)Mathf.Floor(TimeOfDay.Instance.timeUntilDeadline / TimeOfDay.Instance.totalTime)}, DaysUntilDeadline: {TimeOfDay.Instance.daysUntilDeadline}, deadlineDaysAmount: {TimeOfDay.Instance.quotaVariables.deadlineDaysAmount}");
			if ((int)Mathf.Floor(TimeOfDay.Instance.timeUntilDeadline / TimeOfDay.Instance.totalTime) == TimeOfDay.Instance.quotaVariables.deadlineDaysAmount || (int)Mathf.Floor(TimeOfDay.Instance.timeUntilDeadline / TimeOfDay.Instance.totalTime) < 0)
			{
				DayCount++;
				Plugin.Instance.Mls.LogInfo((object)$"New day! Completed days: {DayCount}");
				Plugin.Instance.Mls.LogInfo((object)"New day is also new quota! Skip new day routine..");
			}
			else if ((int)Mathf.Floor(TimeOfDay.Instance.timeUntilDeadline / TimeOfDay.Instance.totalTime) == 0 && ConfigManager.DiscoveryMode)
			{
				Plugin.Instance.Mls.LogInfo((object)"New day is last day of the quota! Not shuffling.");
				ExtendedLevel company = AllLevels.Where((ExtendedLevel level) => level.NumberlessPlanetName == "Gordion").FirstOrDefault();
				if ((Object)(object)company == (Object)null)
				{
					Plugin.Instance.Mls.LogError((object)"Couldn't find company level!");
				}
				else if ((Object)(object)LevelManager.CurrentExtendedLevel != (Object)(object)company)
				{
					Plugin.Instance.Mls.LogInfo((object)"Rerouting ship to company!");
					DelayHelper.Instance.ExecuteAfterDelay(delegate
					{
						StartOfRound.Instance.ChangeLevelServerRpc(company.SelectableLevel.levelID, Terminal.groupCredits);
					}, 3f);
					NetworkManager.Instance.ServerSendAlertMessage(new Notification
					{
						Header = "Deadline!",
						Text = "Auto routing ship to the Company building.",
						Key = "LMU_RerouteCompany"
					});
				}
				else
				{
					Plugin.Instance.Mls.LogInfo((object)"Already at company. No need to reroute.");
				}
			}
			else
			{
				DayCount++;
				Plugin.Instance.Mls.LogInfo((object)$"New day! Completed days: {DayCount}");
				ConfigManager.RefreshConfig();
				if (ConfigManager.DiscoveryMode)
				{
					CollectionExtensions.Do<LMUnlockable>(Unlocks.Where((LMUnlockable unlock) => unlock.NewDiscovery), (Action<LMUnlockable>)delegate(LMUnlockable unlock)
					{
						unlock.NewDiscovery = false;
					});
					ApplyUnlocks();
					if (ConfigManager.DiscoveryShuffleEveryDay)
					{
						Plugin.Instance.Mls.LogInfo((object)"Shuffling moon rotation on new day!");
						ShuffleDiscoverable();
					}
					if (ConfigManager.NewDayDiscoveries && DiscoveryCandidates.Count > 0 && Random.Range(0, 100) < ConfigManager.NewDayDiscoveryChance)
					{
						Plugin.Instance.Mls.LogInfo((object)$"New Day Discovery triggered! (Chance: {ConfigManager.NewDayDiscoveryChance}%)");
						NewDayDiscovery();
					}
				}
				if (ConfigManager.Sales && ConfigManager.SalesShuffleDaily)
				{
					CollectionExtensions.Do<LMUnlockable>((IEnumerable<LMUnlockable>)Unlocks, (Action<LMUnlockable>)delegate(LMUnlockable unlock)
					{
						unlock.RefreshSale();
					});
				}
			}
			LogUnlockables(debug: false);
			NetworkManager.Instance.ServerSendUnlockables(Unlocks, 0