Decompiled source of ProgressivePowers v0.1.0

plugins/ProgressivePowers.dll

Decompiled 15 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using ProgressivePowers.Common;
using ProgressivePowers.Modules;
using SimpleJson;
using UnityEngine;
using UnityEngine.UI;
using YamlDotNet.Serialization;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ProgressivePowers")]
[assembly: AssemblyDescription("Turns the Forsaken powers into passives that deepen as you kill bosses.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ProgressivePowers")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("6b1f0c74-9d2e-4a55-8f31-2c7a4e5b9d10")]
[assembly: AssemblyFileVersion("0.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
namespace ProgressivePowers
{
	internal class Logger
	{
		public static LogLevel Level = (LogLevel)16;

		public static void EnableDebugLogging(object sender, EventArgs e)
		{
			CheckEnableDebugLogging();
		}

		public static void CheckEnableDebugLogging()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (ValConfig.EnableDebugMode.Value)
			{
				Level = (LogLevel)32;
			}
			else
			{
				Level = (LogLevel)16;
			}
		}

		public static void SetDebugLogging(bool state)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (state)
			{
				Level = (LogLevel)32;
			}
			else
			{
				Level = (LogLevel)16;
			}
		}

		public static void LogDebug(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)Level >= 32)
			{
				ProgressivePowers.Log.LogInfo((object)("[DEBUG]" + message));
			}
		}

		public static void LogInfo(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)Level >= 16)
			{
				ProgressivePowers.Log.LogInfo((object)message);
			}
		}

		public static void LogWarning(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)Level >= 4)
			{
				ProgressivePowers.Log.LogWarning((object)message);
			}
		}

		public static void LogError(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)Level >= 2)
			{
				ProgressivePowers.Log.LogError((object)message);
			}
		}
	}
	internal class ValConfig
	{
		public static ConfigFile cfg;

		public static ConfigEntry<bool> EnableDebugMode;

		public static ConfigEntry<int> DebugLevelOverride;

		public static ConfigEntry<float> ConfigApplyDelay;

		public static ConfigEntry<float> KillCreditRange;

		public static ConfigEntry<bool> ShowLockedFeatures;

		public static ConfigEntry<bool> ShowPassiveInStatusBar;

		public static ConfigEntry<bool> BlockPowerActivation;

		public static ConfigEntry<string> LevelRequirementsYaml;

		public const string cfgFolder = "ProgressivePowers";

		public static int Generation { get; private set; }

		public static void MarkChanged()
		{
			Generation++;
		}

		public ValConfig(ConfigFile cf)
		{
			cfg = cf;
			cfg.SaveOnConfigSet = false;
			CreateConfigValues(cf);
			Logger.SetDebugLogging(EnableDebugMode.Value);
		}

		public static void SaveOnSet(bool enabled)
		{
			cfg.SaveOnConfigSet = enabled;
			cfg.Save();
		}

		private void CreateConfigValues(ConfigFile Config)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Expected O, but got Unknown
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Expected O, but got Unknown
			EnableDebugMode = Config.Bind<bool>("Client config", "EnableDebugMode", false, new ConfigDescription("Enables Debug logging.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdvanced = true
			} }));
			EnableDebugMode.SettingChanged += Logger.EnableDebugLogging;
			Logger.CheckEnableDebugLogging();
			DebugLevelOverride = Config.Bind<int>("Client config", "Debug Level Override", -1, new ConfigDescription("Forces every power to this mastery level regardless of kills, for testing. -1 disables the override. Treated as a cheat: only honored after 'devcommands' is enabled in the console, on a world you host.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-1, 7), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdvanced = true
			} }));
			ConfigApplyDelay = BindServerConfig("General", "Config Apply Delay", 1f, "Delay in seconds before a changed config entry is applied in-game. Coalesces a burst of rapid edits (typing, file reloads, server sync) into a single apply. Set to 0 to apply instantly.", advanced: true, 0f, 10f);
			KillCreditRange = BindServerConfig("General", "Kill Credit Range", 200f, "How close you must be when a boss dies to be credited with the kill, in meters. Set to 0 for unlimited range.", advanced: false, 0f, 10000f);
			ShowLockedFeatures = BindServerConfig("General", "Show Locked Features", value: true, "Show not-yet-unlocked features greyed out, along with what you still need to kill.");
			ShowPassiveInStatusBar = BindServerConfig("General", "Show Passive In Status Bar", value: true, "Show the active passive as a permanent icon in the status effect bar.");
			BlockPowerActivation = BindServerConfig("General", "Block Power Activation", value: true, "Prevent Forsaken powers from being activated. Turning this off restores vanilla activation while keeping the passives.");
			LevelRequirementsYaml = cfg.Bind<string>("General", "Level Requirements", "", new ConfigDescription("Serialized contents of ProgressivePowers.Levels.yaml. Edit the file, not this entry - it exists so the server can push requirements to clients.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				Browsable = false
			} }));
			PowerDefinitions.BindConfigs();
			WireChangeNotifications();
		}

		private static void WireChangeNotifications()
		{
			ShowLockedFeatures.SettingChanged += OnChanged;
			ShowPassiveInStatusBar.SettingChanged += OnChanged;
			BlockPowerActivation.SettingChanged += OnChanged;
			DebugLevelOverride.SettingChanged += OnChanged;
			BossPower[] all = PowerDefinitions.All;
			for (int i = 0; i < all.Length; i++)
			{
				PowerFeature[] features = all[i].Features;
				foreach (PowerFeature powerFeature in features)
				{
					if (!(powerFeature is FloatFeature floatFeature))
					{
						if (!(powerFeature is DamageModFeature damageModFeature))
						{
							if (powerFeature is AttributeFeature attributeFeature)
							{
								attributeFeature.Cfg.SettingChanged += OnChanged;
							}
						}
						else
						{
							damageModFeature.Cfg.SettingChanged += OnChanged;
						}
					}
					else
					{
						floatFeature.Cfg.SettingChanged += OnChanged;
					}
				}
			}
			static void OnChanged(object sender, EventArgs e)
			{
				MarkChanged();
				ConfigChangeDebouncer.Schedule("ValConfig", delegate
				{
					PassivePowerManager.Refresh(force: true);
				});
			}
		}

		public static ConfigEntry<float[]> BindServerConfig(string category, string key, float[] value, string description, bool advanced = false, float valMin = 0f, float valMax = 150f)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			return cfg.Bind<float[]>(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(valMin, valMax), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public static ConfigEntry<bool> BindServerConfig(string category, string key, bool value, string description, AcceptableValueBase acceptableValues = null, bool advanced = false)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			return cfg.Bind<bool>(category, key, value, new ConfigDescription(description, acceptableValues, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public static ConfigEntry<int> BindServerConfig(string category, string key, int value, string description, bool advanced = false, int valMin = 0, int valMax = 150)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			return cfg.Bind<int>(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<int>(valMin, valMax), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public static ConfigEntry<float> BindServerConfig(string category, string key, float value, string description, bool advanced = false, float valMin = 0f, float valMax = 150f)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			return cfg.Bind<float>(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(valMin, valMax), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}

		public static ConfigEntry<string> BindServerConfig(string category, string key, string value, string description, AcceptableValueList<string> acceptableValues = null, bool advanced = false)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			return cfg.Bind<string>(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)acceptableValues, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true,
				IsAdvanced = advanced
			} }));
		}
	}
	internal static class KillTracker
	{
		internal const string CustomDataKey = "ProgressivePowers.Kills";

		private static readonly Dictionary<string, int> counts = new Dictionary<string, int>();

		private static Player boundPlayer;

		private static bool loaded;

		private static bool reportedFresh;

		internal static IEnumerable<KeyValuePair<string, int>> All => counts;

		internal static int Get(string yamlName)
		{
			if (!counts.TryGetValue(yamlName, out var value))
			{
				return 0;
			}
			return value;
		}

		internal static void Bind(Player player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				if ((Object)(object)boundPlayer != (Object)(object)player)
				{
					reportedFresh = false;
				}
				boundPlayer = player;
				counts.Clear();
				loaded = false;
				if (player.m_customData.TryGetValue("ProgressivePowers.Kills", out var value) && !string.IsNullOrEmpty(value))
				{
					Parse(value);
					loaded = true;
					Logger.LogDebug("Loaded boss kills for " + player.GetPlayerName() + ": " + Serialize());
				}
				else
				{
					Migrate(player);
				}
			}
		}

		internal static void EnsureLoaded(Player player)
		{
			if (!((Object)(object)player == (Object)null) && (!((Object)(object)boundPlayer == (Object)(object)player) || !loaded))
			{
				Bind(player);
			}
		}

		private static void Migrate(Player player)
		{
			BossPower[] all = PowerDefinitions.All;
			foreach (BossPower bossPower in all)
			{
				if (((Humanoid)player).HaveUniqueKey(bossPower.BossKey))
				{
					counts[bossPower.YamlName] = 1;
				}
			}
			if (counts.Count > 0)
			{
				loaded = true;
				Save(player);
				Logger.LogInfo("No kill record for " + player.GetPlayerName() + "; seeded from defeated_* keys: " + Serialize());
			}
			else if (!reportedFresh)
			{
				reportedFresh = true;
				Logger.LogDebug("No kill record for " + player.GetPlayerName() + " and no defeated_* keys yet; retrying until they load.");
			}
		}

		internal static void RecordKill(Player player, BossPower power)
		{
			EnsureLoaded(player);
			counts.TryGetValue(power.YamlName, out var value);
			counts[power.YamlName] = value + 1;
			boundPlayer = player;
			loaded = true;
			Save(player);
			Logger.LogInfo($"Recorded {power.YamlName} kill #{value + 1}.");
		}

		internal static void Flush(Player player)
		{
			if (!((Object)(object)player == (Object)null) && !((Object)(object)boundPlayer != (Object)(object)player) && loaded)
			{
				Save(player);
			}
		}

		private static void Save(Player player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				player.m_customData["ProgressivePowers.Kills"] = Serialize();
			}
		}

		private static string Serialize()
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyValuePair<string, int> count in counts)
			{
				if (count.Value > 0)
				{
					if (stringBuilder.Length > 0)
					{
						stringBuilder.Append(',');
					}
					stringBuilder.Append(count.Key).Append(':').Append(count.Value);
				}
			}
			return stringBuilder.ToString();
		}

		private static void Parse(string raw)
		{
			string[] array = raw.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(new char[1] { ':' });
				if (array2.Length == 2)
				{
					string text = array2[0].Trim();
					int result;
					if (PowerDefinitions.ByYamlName(text) == null)
					{
						Logger.LogWarning("Ignoring unknown boss '" + text + "' in stored kill counts.");
					}
					else if (int.TryParse(array2[1].Trim(), out result) && result > 0)
					{
						counts[text] = result;
					}
				}
			}
		}
	}
	internal static class LevelRequirements
	{
		private const string FileName = "ProgressivePowers.Levels.yaml";

		private static Dictionary<string, Dictionary<int, Dictionary<string, int>>> table = new Dictionary<string, Dictionary<int, Dictionary<string, int>>>();

		private static FileSystemWatcher watcher;

		private static bool warnedOverrideNeedsCheats;

		internal static string FilePath => Path.Combine(Paths.ConfigPath, "ProgressivePowers", "ProgressivePowers.Levels.yaml");

		internal static void Initialize()
		{
			try
			{
				EnsureFileExists();
				string text = File.ReadAllText(FilePath);
				if (ValConfig.LevelRequirementsYaml.Value != text)
				{
					ValConfig.LevelRequirementsYaml.Value = text;
				}
				ReloadFromConfig();
				StartWatching();
			}
			catch (Exception ex)
			{
				Logger.LogError("Could not initialize level requirements, falling back to defaults: " + ex.Message);
				table = BuildDefaultTable();
			}
			ValConfig.DebugLevelOverride.SettingChanged += delegate
			{
				warnedOverrideNeedsCheats = false;
			};
			ValConfig.LevelRequirementsYaml.SettingChanged += delegate
			{
				ConfigChangeDebouncer.Schedule("LevelRequirements", delegate
				{
					ReloadFromConfig();
					ValConfig.MarkChanged();
					PassivePowerManager.Refresh(force: true);
				});
			};
		}

		private static void EnsureFileExists()
		{
			string directoryName = Path.GetDirectoryName(FilePath);
			if (!Directory.Exists(directoryName))
			{
				Directory.CreateDirectory(directoryName);
			}
			if (!File.Exists(FilePath))
			{
				File.WriteAllText(FilePath, BuildDefaultYaml());
				Logger.LogInfo("Wrote default level requirements to " + FilePath);
			}
		}

		private static void StartWatching()
		{
			watcher = new FileSystemWatcher(Path.GetDirectoryName(FilePath), "ProgressivePowers.Levels.yaml")
			{
				NotifyFilter = (NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.CreationTime),
				EnableRaisingEvents = true
			};
			watcher.Changed += OnFileChanged;
			watcher.Created += OnFileChanged;
			watcher.Renamed += OnFileChanged;
		}

		internal static void Shutdown()
		{
			watcher?.Dispose();
			watcher = null;
		}

		private static void OnFileChanged(object sender, FileSystemEventArgs e)
		{
			ThreadingHelper.Instance.StartSyncInvoke((Action)delegate
			{
				if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer())
				{
					Logger.LogWarning("ProgressivePowers.Levels.yaml changed, but this is a client - the server's level requirements stay in force.");
				}
				else
				{
					ConfigChangeDebouncer.Schedule("OnFileChanged", delegate
					{
						try
						{
							ValConfig.LevelRequirementsYaml.Value = File.ReadAllText(FilePath);
						}
						catch (Exception ex)
						{
							Logger.LogError("Could not re-read ProgressivePowers.Levels.yaml: " + ex.Message);
						}
					});
				}
			});
		}

		private static void ReloadFromConfig()
		{
			string value = ValConfig.LevelRequirementsYaml.Value;
			if (string.IsNullOrWhiteSpace(value))
			{
				table = BuildDefaultTable();
				return;
			}
			Dictionary<string, Dictionary<int, Dictionary<string, int>>> dictionary = Parse(value);
			if (dictionary != null)
			{
				table = dictionary;
			}
		}

		private static Dictionary<string, Dictionary<int, Dictionary<string, int>>> Parse(string text)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, Dictionary<string, Dictionary<string, string>>> dictionary;
			try
			{
				dictionary = new DeserializerBuilder().Build().Deserialize<Dictionary<string, Dictionary<string, Dictionary<string, string>>>>(text);
			}
			catch (Exception ex)
			{
				Logger.LogError("ProgressivePowers.Levels.yaml is not valid YAML, keeping the previous requirements: " + ex.Message);
				return null;
			}
			if (dictionary == null)
			{
				Logger.LogWarning("ProgressivePowers.Levels.yaml is empty, using defaults.");
				return BuildDefaultTable();
			}
			Dictionary<string, Dictionary<int, Dictionary<string, int>>> dictionary2 = new Dictionary<string, Dictionary<int, Dictionary<string, int>>>();
			foreach (KeyValuePair<string, Dictionary<string, Dictionary<string, string>>> item in dictionary)
			{
				if (PowerDefinitions.ByYamlName(item.Key) == null)
				{
					Logger.LogWarning("ProgressivePowers.Levels.yaml: unknown power '" + item.Key + "', ignored.");
					continue;
				}
				Dictionary<int, Dictionary<string, int>> dictionary3 = new Dictionary<int, Dictionary<string, int>>();
				foreach (KeyValuePair<string, Dictionary<string, string>> item2 in item.Value ?? new Dictionary<string, Dictionary<string, string>>())
				{
					if (!int.TryParse(item2.Key, out var result) || result < 1 || result > 7)
					{
						Logger.LogWarning(string.Format("{0}: {1} has level '{2}', expected 1-{3}. Ignored.", "ProgressivePowers.Levels.yaml", item.Key, item2.Key, 7));
						continue;
					}
					Dictionary<string, int> dictionary4 = new Dictionary<string, int>();
					foreach (KeyValuePair<string, string> item3 in item2.Value ?? new Dictionary<string, string>())
					{
						int result2;
						if (PowerDefinitions.ByYamlName(item3.Key) == null)
						{
							Logger.LogWarning(string.Format("{0}: {1} level {2} requires unknown boss '{3}', ignored.", "ProgressivePowers.Levels.yaml", item.Key, result, item3.Key));
						}
						else if (!int.TryParse(item3.Value, out result2) || result2 < 0)
						{
							Logger.LogWarning(string.Format("{0}: {1} level {2} has a bad kill count for '{3}', ignored.", "ProgressivePowers.Levels.yaml", item.Key, result, item3.Key));
						}
						else if (result2 > 0)
						{
							dictionary4[item3.Key] = result2;
						}
					}
					dictionary3[result] = dictionary4;
				}
				if (dictionary3.Count < 7)
				{
					List<string> list = new List<string>();
					for (int i = 1; i <= 7; i++)
					{
						if (!dictionary3.ContainsKey(i))
						{
							list.Add(i.ToString());
						}
					}
					Logger.LogWarning("ProgressivePowers.Levels.yaml: " + item.Key + " does not define level(s) " + string.Join(", ", list) + "; they will unlock for free once the levels below them are met.");
				}
				dictionary2[item.Key] = dictionary3;
			}
			Dictionary<string, Dictionary<int, Dictionary<string, int>>> dictionary5 = null;
			BossPower[] all = PowerDefinitions.All;
			foreach (BossPower bossPower in all)
			{
				if (!dictionary2.ContainsKey(bossPower.YamlName))
				{
					if (dictionary5 == null)
					{
						dictionary5 = BuildDefaultTable();
					}
					dictionary2[bossPower.YamlName] = dictionary5[bossPower.YamlName];
					Logger.LogWarning("ProgressivePowers.Levels.yaml: no entry for '" + bossPower.YamlName + "', using defaults for it.");
				}
			}
			return dictionary2;
		}

		internal static Dictionary<string, int> CumulativeRequirement(BossPower power, int level)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			if (!table.TryGetValue(power.YamlName, out var value))
			{
				return dictionary;
			}
			for (int i = 1; i <= level; i++)
			{
				if (!value.TryGetValue(i, out var value2))
				{
					continue;
				}
				foreach (KeyValuePair<string, int> item in value2)
				{
					if (!dictionary.TryGetValue(item.Key, out var value3) || item.Value > value3)
					{
						dictionary[item.Key] = item.Value;
					}
				}
			}
			return dictionary;
		}

		internal static Dictionary<string, int> Outstanding(BossPower power, int level)
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			foreach (KeyValuePair<string, int> item in CumulativeRequirement(power, level))
			{
				int num = item.Value - KillTracker.Get(item.Key);
				if (num > 0)
				{
					dictionary[item.Key] = num;
				}
			}
			return dictionary;
		}

		internal static int GetLevel(BossPower power)
		{
			int value = ValConfig.DebugLevelOverride.Value;
			if (value >= 0)
			{
				if ((Object)(object)Console.instance != (Object)null && ((Terminal)Console.instance).IsCheatsEnabled())
				{
					return Math.Min(value, 7);
				}
				if (!warnedOverrideNeedsCheats)
				{
					warnedOverrideNeedsCheats = true;
					Logger.LogWarning("Debug Level Override is set but ignored: it requires 'devcommands' in the console, on a world you host.");
				}
			}
			int result = 0;
			for (int i = 1; i <= 7 && Outstanding(power, i).Count <= 0; i++)
			{
				result = i;
			}
			return result;
		}

		private static List<KeyValuePair<string, int>> DefaultLevels(int powerIndex)
		{
			BossPower[] all = PowerDefinitions.All;
			string yamlName = all[powerIndex].YamlName;
			string yamlName2 = all[^1].YamlName;
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			List<KeyValuePair<string, int>> list = new List<KeyValuePair<string, int>>();
			int num = powerIndex;
			bool flag = true;
			for (int i = 1; i <= 7; i++)
			{
				string key;
				int value;
				if (num < all.Length)
				{
					key = all[num].YamlName;
					value = 1;
					num++;
				}
				else
				{
					key = ((yamlName == yamlName2) ? yamlName : (flag ? yamlName : yamlName2));
					flag = !flag;
					dictionary.TryGetValue(key, out var value2);
					value = value2 + 1;
				}
				dictionary[key] = value;
				list.Add(new KeyValuePair<string, int>(key, value));
			}
			return list;
		}

		private static Dictionary<string, Dictionary<int, Dictionary<string, int>>> BuildDefaultTable()
		{
			Dictionary<string, Dictionary<int, Dictionary<string, int>>> dictionary = new Dictionary<string, Dictionary<int, Dictionary<string, int>>>();
			for (int i = 0; i < PowerDefinitions.All.Length; i++)
			{
				Dictionary<int, Dictionary<string, int>> dictionary2 = new Dictionary<int, Dictionary<string, int>>();
				List<KeyValuePair<string, int>> list = DefaultLevels(i);
				for (int j = 0; j < list.Count; j++)
				{
					dictionary2[j + 1] = new Dictionary<string, int> { 
					{
						list[j].Key,
						list[j].Value
					} };
				}
				dictionary[PowerDefinitions.All[i].YamlName] = dictionary2;
			}
			return dictionary;
		}

		private static string BuildDefaultYaml()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("# Progressive Powers - mastery level requirements.");
			stringBuilder.AppendLine("#");
			stringBuilder.AppendLine("# Each power has 7 levels. A level lists boss kill counts; ALL of them must be met,");
			stringBuilder.AppendLine("# and levels are cumulative - reaching level 3 also requires levels 1 and 2. That is");
			stringBuilder.AppendLine("# why each level below only names what it adds.");
			stringBuilder.AppendLine("#");
			stringBuilder.AppendLine("# Counts are repeat kills by your own character, so you can mix them freely:");
			stringBuilder.AppendLine("#   4: { Eikthyr: 3, TheElder: 2 }");
			stringBuilder.AppendLine("# means level 4 needs three Eikthyr kills and two Elder kills.");
			stringBuilder.AppendLine("#");
			stringBuilder.AppendLine("# Valid boss names: " + string.Join(", ", Array.ConvertAll(PowerDefinitions.All, (BossPower p) => p.YamlName)));
			stringBuilder.AppendLine();
			for (int num = 0; num < PowerDefinitions.All.Length; num++)
			{
				stringBuilder.AppendLine(PowerDefinitions.All[num].YamlName + ":");
				List<KeyValuePair<string, int>> list = DefaultLevels(num);
				for (int num2 = 0; num2 < list.Count; num2++)
				{
					stringBuilder.AppendLine($"  {num2 + 1}: {{ {list[num2].Key}: {list[num2].Value} }}");
				}
				stringBuilder.AppendLine();
			}
			return stringBuilder.ToString();
		}
	}
	internal static class PassivePowerManager
	{
		private static bool built;

		private static string lastSignature;

		internal static BossPower CurrentPower { get; private set; }

		internal static int CurrentLevel { get; private set; }

		internal static void BuildPassiveEffects()
		{
			if (built)
			{
				return;
			}
			if ((Object)(object)ObjectDB.instance == (Object)null || (Object)(object)ObjectDB.instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode("GP_Eikthyr")) == (Object)null)
			{
				Logger.LogDebug("ObjectDB is not ready; passives will be built on a later attempt.");
				return;
			}
			BossPower[] all = PowerDefinitions.All;
			foreach (BossPower bossPower in all)
			{
				bossPower.PowerHash = StringExtensionMethods.GetStableHashCode(bossPower.PowerName);
				bossPower.PassiveHash = StringExtensionMethods.GetStableHashCode(bossPower.PassiveName);
				StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(bossPower.PowerHash);
				if ((Object)(object)statusEffect == (Object)null)
				{
					Logger.LogWarning("Vanilla status effect '" + bossPower.PowerName + "' was not found in ObjectDB; '" + bossPower.PassiveName + "' will have no icon.");
				}
				SE_Stats val = ScriptableObject.CreateInstance<SE_Stats>();
				((Object)val).name = bossPower.PassiveName;
				((Object)val).hideFlags = (HideFlags)61;
				((StatusEffect)val).m_name = (((Object)(object)statusEffect != (Object)null) ? statusEffect.m_name : bossPower.LocKey);
				((StatusEffect)val).m_icon = (((Object)(object)statusEffect != (Object)null) ? statusEffect.m_icon : null);
				((StatusEffect)val).m_category = "";
				((StatusEffect)val).m_startMessage = "";
				((StatusEffect)val).m_stopMessage = "";
				((StatusEffect)val).m_repeatMessage = "";
				((StatusEffect)val).m_repeatInterval = 0f;
				bossPower.PassiveSE = val;
				Neutralize(val);
			}
			built = true;
			Logger.LogInfo($"Built {PowerDefinitions.All.Length} passive power effects.");
			Refresh(force: true);
		}

		internal static void Refresh(bool force = false)
		{
			if (!built)
			{
				BuildPassiveEffects();
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !built)
			{
				lastSignature = null;
				return;
			}
			KillTracker.EnsureLoaded(localPlayer);
			BossPower bossPower = PowerDefinitions.ByPowerName(localPlayer.GetGuardianPowerName());
			int num = ((bossPower != null) ? LevelRequirements.GetLevel(bossPower) : 0);
			CurrentPower = bossPower;
			CurrentLevel = num;
			SEMan sEMan = ((Character)localPlayer).GetSEMan();
			string text = $"{bossPower?.PassiveName}|{num}|{ValConfig.Generation}";
			if (!force && text == lastSignature && StateMatches(sEMan, bossPower, num))
			{
				return;
			}
			lastSignature = text;
			BossPower[] all = PowerDefinitions.All;
			foreach (BossPower bossPower2 in all)
			{
				if (bossPower2.PassiveHash != 0)
				{
					sEMan.RemoveStatusEffect(bossPower2.PassiveHash, true);
				}
			}
			if (bossPower == null || num <= 0)
			{
				Logger.LogDebug((bossPower == null) ? "No power selected." : (bossPower.YamlName + " is at level 0; no passive applied."));
				return;
			}
			BuildPassive(bossPower, num);
			sEMan.AddStatusEffect((StatusEffect)(object)bossPower.PassiveSE, true, 0, 0f, (short)(-1));
			Logger.LogDebug($"Applied {bossPower.PassiveName} at level {num}/{7}.");
		}

		private static bool StateMatches(SEMan seman, BossPower want, int level)
		{
			BossPower[] all = PowerDefinitions.All;
			foreach (BossPower bossPower in all)
			{
				bool flag = bossPower == want && level > 0;
				if (seman.HaveStatusEffect(bossPower.PassiveHash) != flag)
				{
					return false;
				}
			}
			return true;
		}

		internal static void BuildPassive(BossPower power, int level)
		{
			SE_Stats passiveSE = power.PassiveSE;
			Neutralize(passiveSE);
			PassiveBuild build = new PassiveBuild(passiveSE);
			for (int i = 0; i < level && i < power.Features.Length; i++)
			{
				PowerFeature powerFeature = power.Features[i];
				if (powerFeature.Enabled)
				{
					powerFeature.Apply(build);
				}
			}
			if (!ValConfig.ShowPassiveInStatusBar.Value)
			{
				((StatusEffect)passiveSE).m_icon = null;
			}
			else
			{
				RestoreIcon(power);
			}
		}

		private static void RestoreIcon(BossPower power)
		{
			if (!((Object)(object)((StatusEffect)power.PassiveSE).m_icon != (Object)null) && !((Object)(object)ObjectDB.instance == (Object)null))
			{
				StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(power.PowerHash);
				if ((Object)(object)statusEffect != (Object)null)
				{
					((StatusEffect)power.PassiveSE).m_icon = statusEffect.m_icon;
				}
			}
		}

		private static void Neutralize(SE_Stats se)
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			((StatusEffect)se).m_ttl = 0f;
			((StatusEffect)se).m_cooldown = 0f;
			se.m_runStaminaDrainModifier = 0f;
			se.m_jumpStaminaUseModifier = 0f;
			se.m_swimStaminaUseModifier = 0f;
			se.m_dodgeStaminaUseModifier = 0f;
			se.m_attackStaminaUseModifier = 0f;
			se.m_blockStaminaUseModifier = 0f;
			se.m_blockStaminaUseFlatValue = 0f;
			se.m_sneakStaminaUseModifier = 0f;
			se.m_homeItemStaminaUseModifier = 0f;
			se.m_speedModifier = 0f;
			se.m_swimSpeedModifier = 0f;
			se.m_jumpModifier = Vector3.zero;
			se.m_windMovementModifier = 0f;
			se.m_windRunStaminaModifier = 0f;
			se.m_fallDamageModifier = 0f;
			se.m_maxMaxFallSpeed = 0f;
			se.m_healthRegenMultiplier = 1f;
			se.m_staminaRegenMultiplier = 1f;
			se.m_eitrRegenMultiplier = 1f;
			se.m_addArmor = 0f;
			se.m_armorMultiplier = 0f;
			se.m_addMaxCarryWeight = 0f;
			se.m_noiseModifier = 0f;
			se.m_stealthModifier = 0f;
			se.m_adrenalineModifier = 0f;
			se.m_staggerModifier = 0f;
			se.m_timedBlockBonus = 0f;
			se.m_raiseSkill = (SkillType)0;
			se.m_raiseSkillModifier = 0f;
			se.m_skillLevel = (SkillType)0;
			se.m_skillLevelModifier = 0f;
			se.m_skillLevel2 = (SkillType)0;
			se.m_skillLevelModifier2 = 0f;
			se.m_tickInterval = 0f;
			se.m_healthPerTick = 0f;
			se.m_healthPerTickMinHealthPercentage = 0f;
			se.m_mods = new List<DamageModPair>();
			se.m_percentigeDamageModifiers = default(DamageTypes);
			se.m_modifyAttackSkill = (SkillType)0;
			se.m_damageModifier = 1f;
			((StatusEffect)se).m_attributes = (StatusAttribute)0;
		}
	}
	internal sealed class BossPower
	{
		internal string PowerName;

		internal string PassiveName;

		internal string BossKey;

		internal string YamlName;

		internal string LocKey;

		internal string ConfigCategory;

		internal PowerFeature[] Features;

		internal int PowerHash;

		internal int PassiveHash;

		internal SE_Stats PassiveSE;

		internal const int MaxLevel = 7;
	}
	internal static class PowerDefinitions
	{
		internal static readonly BossPower[] All = Build();

		private static Dictionary<string, BossPower> byPowerName;

		private static Dictionary<string, BossPower> byYamlName;

		private const float PctMin = -1f;

		private const float PctMax = 5f;

		internal static BossPower ByPowerName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return null;
			}
			if (byPowerName == null)
			{
				byPowerName = All.ToDictionary((BossPower p) => p.PowerName);
			}
			if (!byPowerName.TryGetValue(name, out var value))
			{
				return null;
			}
			return value;
		}

		internal static BossPower ByYamlName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return null;
			}
			if (byYamlName == null)
			{
				byYamlName = All.ToDictionary((BossPower p) => p.YamlName);
			}
			if (!byYamlName.TryGetValue(name, out var value))
			{
				return null;
			}
			return value;
		}

		internal static BossPower ByBossKey(string key)
		{
			if (string.IsNullOrEmpty(key))
			{
				return null;
			}
			BossPower[] all = All;
			foreach (BossPower bossPower in all)
			{
				if (string.Equals(bossPower.BossKey, key, StringComparison.OrdinalIgnoreCase))
				{
					return bossPower;
				}
			}
			return null;
		}

		internal static void BindConfigs()
		{
			BossPower[] all = All;
			foreach (BossPower bossPower in all)
			{
				PowerFeature[] features = bossPower.Features;
				for (int j = 0; j < features.Length; j++)
				{
					features[j].Bind(bossPower.ConfigCategory);
				}
			}
		}

		private static BossPower[] Build()
		{
			return new BossPower[7]
			{
				new BossPower
				{
					PowerName = "GP_Eikthyr",
					PassiveName = "PP_Eikthyr",
					BossKey = "defeated_eikthyr",
					YamlName = "Eikthyr",
					LocKey = "$pp_power_eikthyr",
					ConfigCategory = "Power 1 - Eikthyr",
					Features = new PowerFeature[7]
					{
						new FloatFeature("$pp_feature_eikthyr_1", "Feature 1 - Run stamina cost", "Fraction by which running stamina drain changes. Negative is cheaper.", -0.3f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_runStaminaDrainModifier = v;
						}),
						new FloatFeature("$pp_feature_eikthyr_2", "Feature 2 - Jump stamina cost", "Fraction by which jump stamina cost changes. Negative is cheaper.", -0.3f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_jumpStaminaUseModifier = v;
						}),
						new FloatFeature("$pp_feature_eikthyr_3", "Feature 3 - Swim stamina cost", "Fraction by which swim stamina cost changes. Negative is cheaper.", -0.3f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_swimStaminaUseModifier = v;
						}),
						new FloatFeature("$pp_feature_eikthyr_4", "Feature 4 - Movement speed", "Fraction added to movement speed.", 0.03f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_speedModifier = v;
						}),
						new FloatFeature("$pp_feature_eikthyr_5", "Feature 5 - Stamina regeneration", "Fraction added to stamina regeneration.", 0.15f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_staminaRegenMultiplier = 1f + v;
						}),
						new FloatFeature("$pp_feature_eikthyr_6", "Feature 6 - Fall damage", "Fraction by which fall damage changes. Negative takes less.", -0.35f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_fallDamageModifier = v;
						}),
						new FloatFeature("$pp_feature_eikthyr_7", "Feature 7 - Dodge stamina cost", "Fraction by which dodge stamina cost changes. Negative is cheaper.", -0.25f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_dodgeStaminaUseModifier = v;
						})
					}
				},
				new BossPower
				{
					PowerName = "GP_TheElder",
					PassiveName = "PP_TheElder",
					BossKey = "defeated_gdking",
					YamlName = "TheElder",
					LocKey = "$pp_power_theelder",
					ConfigCategory = "Power 2 - The Elder",
					Features = new PowerFeature[7]
					{
						new FloatFeature("$pp_feature_theelder_1", "Feature 1 - Health regeneration", "Fraction added to health regeneration.", 0.15f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_healthRegenMultiplier = 1f + v;
						}),
						new FloatFeature("$pp_feature_theelder_2", "Feature 2 - Chopping damage", "Fraction added to chop damage against trees.", 0.3f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_percentigeDamageModifiers.m_chop += v;
						}),
						new FloatFeature("$pp_feature_theelder_3", "Feature 3 - Pickaxe damage", "Fraction added to pickaxe damage against rock and ore.", 0.3f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_percentigeDamageModifiers.m_pickaxe += v;
						}),
						new FloatFeature("$pp_feature_theelder_4", "Feature 4 - Carry weight", "Extra carry weight in units.", 75f, 0f, 1000f, ValueDisplay.Flat, delegate(PassiveBuild b, float v)
						{
							SE_Stats se = b.Se;
							se.m_addMaxCarryWeight += v;
						}),
						new FloatFeature("$pp_feature_theelder_5", "Feature 5 - Woodcutting skill", "Effective Woodcutting skill levels added.", 12f, 0f, 100f, ValueDisplay.Flat, delegate(PassiveBuild b, float v)
						{
							b.AddSkillLevel((SkillType)13, v);
						}),
						new FloatFeature("$pp_feature_theelder_6", "Feature 6 - Pickaxes skill", "Effective Pickaxes skill levels added.", 12f, 0f, 100f, ValueDisplay.Flat, delegate(PassiveBuild b, float v)
						{
							b.AddSkillLevel((SkillType)12, v);
						}),
						new FloatFeature("$pp_feature_theelder_7", "Feature 7 - Regeneration tick", "Health healed every 10 seconds.", 1f, 0f, 50f, ValueDisplay.Flat, delegate(PassiveBuild b, float v)
						{
							b.Se.m_tickInterval = 10f;
							b.Se.m_healthPerTick = v;
						})
					}
				},
				new BossPower
				{
					PowerName = "GP_Bonemass",
					PassiveName = "PP_Bonemass",
					BossKey = "defeated_bonemass",
					YamlName = "Bonemass",
					LocKey = "$pp_power_bonemass",
					ConfigCategory = "Power 3 - Bonemass",
					Features = new PowerFeature[7]
					{
						new DamageModFeature("$pp_feature_bonemass_1", "Feature 1 - Blunt resistance", "Resistance to blunt damage.", (DamageType)1, (DamageModifier)7),
						new DamageModFeature("$pp_feature_bonemass_2", "Feature 2 - Slash resistance", "Resistance to slash damage.", (DamageType)2, (DamageModifier)7),
						new DamageModFeature("$pp_feature_bonemass_3", "Feature 3 - Pierce resistance", "Resistance to pierce damage.", (DamageType)4, (DamageModifier)7),
						new FloatFeature("$pp_feature_bonemass_4", "Feature 4 - Block stamina cost", "Fraction by which blocking stamina cost changes. Negative is cheaper.", -0.5f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_blockStaminaUseModifier = v;
						}),
						new DamageModFeature("$pp_feature_bonemass_5", "Feature 5 - Poison resistance", "Resistance to poison damage.", (DamageType)256, (DamageModifier)1),
						new FloatFeature("$pp_feature_bonemass_6", "Feature 6 - Armor", "Flat armor added.", 6f, 0f, 200f, ValueDisplay.Flat, delegate(PassiveBuild b, float v)
						{
							SE_Stats se = b.Se;
							se.m_addArmor += v;
						}),
						new FloatFeature("$pp_feature_bonemass_7", "Feature 7 - Stagger taken", "Fraction by which stagger buildup changes. Negative staggers less.", -0.25f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_staggerModifier = v;
						})
					}
				},
				new BossPower
				{
					PowerName = "GP_Moder",
					PassiveName = "PP_Moder",
					BossKey = "defeated_dragon",
					YamlName = "Moder",
					LocKey = "$pp_power_moder",
					ConfigCategory = "Power 4 - Moder",
					Features = new PowerFeature[7]
					{
						new DamageModFeature("$pp_feature_moder_1", "Feature 1 - Frost resistance", "Resistance to frost damage.", (DamageType)64, (DamageModifier)1),
						new AttributeFeature("$pp_feature_moder_2", "Feature 2 - Cold immunity", "Grants the cold resistance attribute, so freezing weather no longer harms you.", (StatusAttribute)1),
						new AttributeFeature("$pp_feature_moder_3", "Feature 3 - Sailing tailwind", "Grants the sailing power attribute, so ships you crew always have the wind behind them.", (StatusAttribute)4),
						new FloatFeature("$pp_feature_moder_4", "Feature 4 - Carry weight", "Extra carry weight in units.", 150f, 0f, 1000f, ValueDisplay.Flat, delegate(PassiveBuild b, float v)
						{
							SE_Stats se = b.Se;
							se.m_addMaxCarryWeight += v;
						}),
						new FloatFeature("$pp_feature_moder_5", "Feature 5 - Movement speed", "Fraction added to movement speed.", 0.05f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_speedModifier = v;
						}),
						new FloatFeature("$pp_feature_moder_6", "Feature 6 - Wind at your back", "Fraction by which running with the wind speeds you up and drains less stamina.", 0.25f, 0f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_windMovementModifier = v;
							b.Se.m_windRunStaminaModifier = 0f - v;
						}),
						new FloatFeature("$pp_feature_moder_7", "Feature 7 - Swim speed", "Fraction added to swim speed.", 0.25f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_swimSpeedModifier = v;
						})
					}
				},
				new BossPower
				{
					PowerName = "GP_Yagluth",
					PassiveName = "PP_Yagluth",
					BossKey = "defeated_goblinking",
					YamlName = "Yagluth",
					LocKey = "$pp_power_yagluth",
					ConfigCategory = "Power 5 - Yagluth",
					Features = new PowerFeature[7]
					{
						new DamageModFeature("$pp_feature_yagluth_1", "Feature 1 - Lightning resistance", "Resistance to lightning damage.", (DamageType)128, (DamageModifier)1),
						new FloatFeature("$pp_feature_yagluth_2", "Feature 2 - Melee damage", "Fraction added to blunt, slash and pierce damage you deal.", 0.05f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_percentigeDamageModifiers.m_blunt += v;
							b.Se.m_percentigeDamageModifiers.m_slash += v;
							b.Se.m_percentigeDamageModifiers.m_pierce += v;
						}),
						new FloatFeature("$pp_feature_yagluth_3", "Feature 3 - Farming skill", "Effective Farming skill levels added.", 12f, 0f, 100f, ValueDisplay.Flat, delegate(PassiveBuild b, float v)
						{
							b.AddSkillLevel((SkillType)106, v);
						}),
						new FloatFeature("$pp_feature_yagluth_4", "Feature 4 - Elemental damage", "Fraction added to fire, frost, lightning, poison and spirit damage you deal.", 0.05f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_percentigeDamageModifiers.m_fire += v;
							b.Se.m_percentigeDamageModifiers.m_frost += v;
							b.Se.m_percentigeDamageModifiers.m_lightning += v;
							b.Se.m_percentigeDamageModifiers.m_poison += v;
							b.Se.m_percentigeDamageModifiers.m_spirit += v;
						}),
						new FloatFeature("$pp_feature_yagluth_5", "Feature 5 - Skill gain rate", "Fraction added to how fast every skill is raised.", 0.15f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							//IL_000b: Unknown result type (might be due to invalid IL or missing references)
							b.Se.m_raiseSkill = (SkillType)999;
							b.Se.m_raiseSkillModifier = v;
						}),
						new FloatFeature("$pp_feature_yagluth_6", "Feature 6 - Armor multiplier", "Fraction added to total armor.", 0.1f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_armorMultiplier = v;
						}),
						new FloatFeature("$pp_feature_yagluth_7", "Feature 7 - Mastery, all damage", "Fraction added to every damage type you deal, on top of features 2 and 4.", 0.05f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_percentigeDamageModifiers.m_damage += v;
							b.Se.m_percentigeDamageModifiers.m_blunt += v;
							b.Se.m_percentigeDamageModifiers.m_slash += v;
							b.Se.m_percentigeDamageModifiers.m_pierce += v;
							b.Se.m_percentigeDamageModifiers.m_chop += v;
							b.Se.m_percentigeDamageModifiers.m_pickaxe += v;
							b.Se.m_percentigeDamageModifiers.m_fire += v;
							b.Se.m_percentigeDamageModifiers.m_frost += v;
							b.Se.m_percentigeDamageModifiers.m_lightning += v;
							b.Se.m_percentigeDamageModifiers.m_poison += v;
							b.Se.m_percentigeDamageModifiers.m_spirit += v;
						})
					}
				},
				new BossPower
				{
					PowerName = "GP_Queen",
					PassiveName = "PP_Queen",
					BossKey = "defeated_queen",
					YamlName = "Queen",
					LocKey = "$pp_power_queen",
					ConfigCategory = "Power 6 - The Queen",
					Features = new PowerFeature[7]
					{
						new DamageModFeature("$pp_feature_queen_1", "Feature 1 - Poison resistance", "Resistance to poison damage.", (DamageType)256, (DamageModifier)1),
						new FloatFeature("$pp_feature_queen_2", "Feature 2 - Sneak stamina cost", "Fraction by which sneaking stamina cost changes. Negative is cheaper.", -0.5f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_sneakStaminaUseModifier = v;
						}),
						new FloatFeature("$pp_feature_queen_3", "Feature 3 - Eitr regeneration", "Fraction added to eitr regeneration.", 0.5f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_eitrRegenMultiplier = 1f + v;
						}),
						new FloatFeature("$pp_feature_queen_4", "Feature 4 - Stealth", "Fraction added to how hidden you are while sneaking.", 0.25f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_stealthModifier = v;
						}),
						new FloatFeature("$pp_feature_queen_5", "Feature 5 - Noise", "Fraction by which the noise you make changes. Negative is quieter.", -0.25f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_noiseModifier = v;
						}),
						new FloatFeature("$pp_feature_queen_6", "Feature 6 - Elemental Magic skill", "Effective Elemental Magic skill levels added.", 12f, 0f, 100f, ValueDisplay.Flat, delegate(PassiveBuild b, float v)
						{
							b.AddSkillLevel((SkillType)9, v);
						}),
						new FloatFeature("$pp_feature_queen_7", "Feature 7 - Blood Magic skill", "Effective Blood Magic skill levels added.", 12f, 0f, 100f, ValueDisplay.Flat, delegate(PassiveBuild b, float v)
						{
							b.AddSkillLevel((SkillType)10, v);
						})
					}
				},
				new BossPower
				{
					PowerName = "GP_Fader",
					PassiveName = "PP_Fader",
					BossKey = "defeated_fader",
					YamlName = "Fader",
					LocKey = "$pp_power_fader",
					ConfigCategory = "Power 7 - Fader",
					Features = new PowerFeature[7]
					{
						new DamageModFeature("$pp_feature_fader_1", "Feature 1 - Fire resistance", "Resistance to fire damage.", (DamageType)32, (DamageModifier)1),
						new FloatFeature("$pp_feature_fader_2", "Feature 2 - Adrenaline gain", "Fraction added to adrenaline gained in combat.", 0.5f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_adrenalineModifier = v;
						}),
						new FloatFeature("$pp_feature_fader_3", "Feature 3 - Stagger taken", "Fraction by which stagger buildup changes. Negative staggers less.", -0.25f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_staggerModifier = v;
						}),
						new FloatFeature("$pp_feature_fader_4", "Feature 4 - Attack stamina cost", "Fraction by which attack stamina cost changes. Negative is cheaper.", -0.2f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_attackStaminaUseModifier = v;
						}),
						new FloatFeature("$pp_feature_fader_5", "Feature 5 - Armor", "Flat armor added.", 8f, 0f, 200f, ValueDisplay.Flat, delegate(PassiveBuild b, float v)
						{
							SE_Stats se = b.Se;
							se.m_addArmor += v;
						}),
						new FloatFeature("$pp_feature_fader_6", "Feature 6 - Timed block bonus", "Fraction added to the parry bonus of a timed block.", 0.5f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_timedBlockBonus = v;
						}),
						new FloatFeature("$pp_feature_fader_7", "Feature 7 - Health regeneration", "Fraction added to health regeneration.", 0.2f, -1f, 5f, ValueDisplay.Percent, delegate(PassiveBuild b, float v)
						{
							b.Se.m_healthRegenMultiplier = 1f + v;
						})
					}
				}
			};
		}
	}
	[BepInPlugin("MidnightsFX.ProgressivePowers", "ProgressivePowers", "0.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal class ProgressivePowers : BaseUnityPlugin
	{
		public const string PluginGUID = "MidnightsFX.ProgressivePowers";

		public const string PluginName = "ProgressivePowers";

		public const string PluginVersion = "0.1.0";

		internal static ManualLogSource Log;

		internal ValConfig cfg;

		public static CustomLocalization Localization = LocalizationManager.Instance.GetLocalization();

		private const float RefreshInterval = 2f;

		private Harmony harmony;

		public void Awake()
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			cfg = new ValConfig(((BaseUnityPlugin)this).Config);
			LocalizationLoader.AddLocalizations();
			LevelRequirements.Initialize();
			PrefabManager.OnVanillaPrefabsAvailable += PassivePowerManager.BuildPassiveEffects;
			SynchronizationManager.OnConfigurationSynchronized += delegate
			{
				ValConfig.MarkChanged();
				PassivePowerManager.Refresh(force: true);
			};
			harmony = new Harmony("MidnightsFX.ProgressivePowers");
			harmony.PatchAll(typeof(ProgressivePowers).Assembly);
			((MonoBehaviour)this).InvokeRepeating("SafetyNetTick", 2f, 2f);
			ValConfig.SaveOnSet(enabled: true);
		}

		private void SafetyNetTick()
		{
			PassivePowerManager.Refresh();
		}

		public void OnDestroy()
		{
			((MonoBehaviour)this).CancelInvoke("SafetyNetTick");
			PrefabManager.OnVanillaPrefabsAvailable -= PassivePowerManager.BuildPassiveEffects;
			LevelRequirements.Shutdown();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
}
namespace ProgressivePowers.Patches
{
	[HarmonyPatch(typeof(Player), "StartGuardianPower")]
	internal static class BlockStartGuardianPower
	{
		private static bool Prefix(Player __instance, ref bool __result)
		{
			if (!ValConfig.BlockPowerActivation.Value)
			{
				return true;
			}
			__result = false;
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				((Character)__instance).Message((MessageType)2, "$pp_cannot_activate", 0, (Sprite)null, false);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Player), "ActivateGuardianPower")]
	internal static class BlockActivateGuardianPower
	{
		private static bool Prefix(ref bool __result)
		{
			if (!ValConfig.BlockPowerActivation.Value)
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	internal static class KillPersistence
	{
		[HarmonyPatch(typeof(Player), "Load")]
		internal static class LoadKills
		{
			private static void Postfix(Player __instance)
			{
				if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					KillTracker.Bind(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Save")]
		internal static class SaveKills
		{
			private static void Prefix(Player __instance)
			{
				if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					KillTracker.Flush(__instance);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "SetGuardianPower")]
	internal static class OnSetGuardianPower
	{
		private static void Postfix(Player __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				__instance.m_guardianPowerCooldown = 0f;
				PassivePowerManager.Refresh(force: true);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "OnSpawned")]
	internal static class OnPlayerSpawned
	{
		private static void Postfix(Player __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				__instance.m_guardianPowerCooldown = 0f;
				KillTracker.EnsureLoaded(__instance);
				PassivePowerManager.Refresh(force: true);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "OnRespawn")]
	internal static class OnPlayerRespawn
	{
		private static void Postfix(Player __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				PassivePowerManager.Refresh(force: true);
			}
		}
	}
	internal static class KillBroadcast
	{
		[HarmonyPatch(typeof(Game), "Start")]
		internal static class RegisterKillRpc
		{
			private static void Postfix()
			{
				ZRoutedRpc.instance.Register<string, Vector3>("MidnightsFX.ProgressivePowers.BossKill", (Action<long, string, Vector3>)OnBossKill);
			}
		}

		internal struct KillSite
		{
			internal bool Owned;

			internal Vector3 Position;
		}

		[HarmonyPatch(typeof(Character), "OnDeath")]
		internal static class CountBossKills
		{
			private static void Prefix(Character __instance, out KillSite __state)
			{
				//IL_003f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				__state = default(KillSite);
				if (!string.IsNullOrEmpty(__instance.m_defeatSetGlobalKey) && !((Object)(object)__instance.m_nview == (Object)null) && __instance.m_nview.IsOwner())
				{
					__state.Owned = true;
					__state.Position = ((Component)__instance).transform.position;
				}
			}

			private static void Postfix(Character __instance, KillSite __state)
			{
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				if (__state.Owned)
				{
					BossPower bossPower = PowerDefinitions.ByBossKey(__instance.m_defeatSetGlobalKey);
					if (bossPower != null)
					{
						ZRoutedRpc.instance.InvokeRoutedRPC(0L, "MidnightsFX.ProgressivePowers.BossKill", new object[2] { bossPower.YamlName, __state.Position });
					}
				}
			}
		}

		private const string RpcName = "MidnightsFX.ProgressivePowers.BossKill";

		private static void OnBossKill(long sender, string yamlName, Vector3 pos)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			BossPower bossPower = PowerDefinitions.ByYamlName(yamlName);
			if (bossPower == null)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				float value = ValConfig.KillCreditRange.Value;
				if (value > 0f && Vector3.Distance(((Component)localPlayer).transform.position, pos) > value)
				{
					Logger.LogDebug($"{bossPower.YamlName} died outside the {value}m credit range; no kill recorded.");
					return;
				}
				KillTracker.RecordKill(localPlayer, bossPower);
				PassivePowerManager.Refresh(force: true);
			}
		}
	}
	[HarmonyPatch(typeof(SE_Stats), "GetTooltipString")]
	internal static class PowerTooltipText
	{
		private static void Postfix(SE_Stats __instance, ref string __result)
		{
			BossPower bossPower = PowerTooltips.Match(((Object)__instance).name);
			if (bossPower != null)
			{
				__result = PowerTooltips.Build(bossPower);
			}
		}
	}
	[HarmonyPatch(typeof(ItemStand), "GetHoverText")]
	internal static class BossStoneHoverText
	{
		private static void Postfix(ItemStand __instance, ref string __result)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance.m_guardianPower == (Object)null) && !__instance.m_canBeRemoved && !((Object)(object)Player.m_localPlayer == (Object)null) && !string.IsNullOrEmpty(__result) && __instance.HaveAttachment() && PrivateArea.CheckAccess(((Component)__instance).transform.position, 0f, false, false))
			{
				BossPower bossPower = PowerDefinitions.ByPowerName(((Object)__instance.m_guardianPower).name);
				if (bossPower != null)
				{
					bool flag = Player.m_localPlayer.GetGuardianPowerName() == ((Object)__instance.m_guardianPower).name;
					string text = Localization.instance.Localize("<color=orange>" + __instance.m_guardianPower.m_name + "</color>");
					string text2 = Localization.instance.Localize(flag ? "$pp_attuned" : "[<color=yellow><b>$KEY_Use</b></color>] $pp_attune");
					__result = text + "\n" + PowerTooltips.Build(bossPower) + "\n\n" + text2;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Hud), "UpdateGuardianPower")]
	internal static class GuardianPowerHudLevel
	{
		private static void Postfix(Hud __instance, Player player)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && PassivePowerManager.CurrentPower != null && !((Object)(object)__instance.m_gpRoot == (Object)null) && ((Component)__instance.m_gpRoot).gameObject.activeSelf)
			{
				if ((Object)(object)__instance.m_gpCooldown != (Object)null)
				{
					__instance.m_gpCooldown.text = $"{PassivePowerManager.CurrentLevel}/{7}";
				}
				if ((Object)(object)__instance.m_gpIcon != (Object)null)
				{
					((Graphic)__instance.m_gpIcon).color = Color.white;
				}
			}
		}
	}
}
namespace ProgressivePowers.Modules
{
	internal enum ValueDisplay
	{
		Percent,
		Flat
	}
	internal sealed class PassiveBuild
	{
		internal readonly SE_Stats Se;

		private int usedSkillSlots;

		internal PassiveBuild(SE_Stats se)
		{
			Se = se;
		}

		internal void AddDamageMod(DamageType type, DamageModifier modifier)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			Se.m_mods.Add(new DamageModPair
			{
				m_type = type,
				m_modifier = modifier
			});
		}

		internal void AddSkillLevel(SkillType skill, float modifier)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (usedSkillSlots == 0)
			{
				Se.m_skillLevel = skill;
				Se.m_skillLevelModifier = modifier;
				usedSkillSlots = 1;
			}
			else if (usedSkillSlots == 1)
			{
				Se.m_skillLevel2 = skill;
				Se.m_skillLevelModifier2 = modifier;
				usedSkillSlots = 2;
			}
			else
			{
				Logger.LogWarning($"{((Object)Se).name}: more than two skill-level features are active; '{skill}' was dropped. SE_Stats only has two slots.");
			}
		}
	}
	internal abstract class PowerFeature
	{
		internal string LocKey;

		internal string ConfigKey;

		internal string Description;

		internal abstract bool Enabled { get; }

		internal abstract void Bind(string category);

		internal abstract void Apply(PassiveBuild build);

		internal abstract string ValueText();

		internal string Describe()
		{
			return Localization.instance.Localize(LocKey).Replace("$1", ValueText());
		}

		protected static string Signed(float value, ValueDisplay display)
		{
			float num = ((display == ValueDisplay.Percent) ? (value * 100f) : value);
			string arg = ((num > 0f) ? "+" : "");
			if (display != ValueDisplay.Percent)
			{
				return $"{arg}{num:0.#}";
			}
			return $"{arg}{num:0.#}%";
		}
	}
	internal sealed class FloatFeature : PowerFeature
	{
		private readonly float defaultValue;

		private readonly float min;

		private readonly float max;

		private readonly ValueDisplay display;

		private readonly Action<PassiveBuild, float> apply;

		internal ConfigEntry<float> Cfg;

		internal override bool Enabled
		{
			get
			{
				if (Cfg != null)
				{
					return Mathf.Abs(Cfg.Value) > 0.0001f;
				}
				return false;
			}
		}

		internal FloatFeature(string locKey, string configKey, string description, float defaultValue, float min, float max, ValueDisplay display, Action<PassiveBuild, float> apply)
		{
			LocKey = locKey;
			ConfigKey = configKey;
			Description = description;
			this.defaultValue = defaultValue;
			this.min = min;
			this.max = max;
			this.display = display;
			this.apply = apply;
		}

		internal override void Bind(string category)
		{
			Cfg = ValConfig.BindServerConfig(category, ConfigKey, defaultValue, Description + " Set to 0 to disable.", advanced: false, min, max);
		}

		internal override void Apply(PassiveBuild build)
		{
			apply(build, Cfg.Value);
		}

		internal override string ValueText()
		{
			return PowerFeature.Signed((Cfg == null) ? defaultValue : Cfg.Value, display);
		}
	}
	internal sealed class DamageModFeature : PowerFeature
	{
		internal static readonly string[] Choices = new string[5] { "Normal", "SlightlyResistant", "Resistant", "VeryResistant", "Immune" };

		private readonly DamageType damageType;

		private readonly string defaultValue;

		internal ConfigEntry<string> Cfg;

		internal override bool Enabled => (int)Current() > 0;

		internal unsafe DamageModFeature(string locKey, string configKey, string description, DamageType damageType, DamageModifier defaultValue)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			LocKey = locKey;
			ConfigKey = configKey;
			Description = description;
			this.damageType = damageType;
			this.defaultValue = ((object)(*(DamageModifier*)(&defaultValue))/*cast due to .constrained prefix*/).ToString();
		}

		internal override void Bind(string category)
		{
			Cfg = ValConfig.BindServerConfig(category, ConfigKey, defaultValue, Description + " Set to Normal to disable.", new AcceptableValueList<string>(Choices));
		}

		private DamageModifier Current()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (!Enum.TryParse<DamageModifier>((Cfg == null) ? defaultValue : Cfg.Value, out DamageModifier result))
			{
				return (DamageModifier)0;
			}
			return result;
		}

		internal override void Apply(PassiveBuild build)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			build.AddDamageMod(damageType, Current());
		}

		internal override string ValueText()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			return Localization.instance.Localize("$pp_dmgmod_" + ((object)Current()/*cast due to .constrained prefix*/).ToString().ToLowerInvariant());
		}
	}
	internal sealed class AttributeFeature : PowerFeature
	{
		private readonly StatusAttribute attribute;

		private readonly bool defaultValue;

		internal ConfigEntry<bool> Cfg;

		internal override bool Enabled
		{
			get
			{
				if (Cfg != null)
				{
					return Cfg.Value;
				}
				return defaultValue;
			}
		}

		internal AttributeFeature(string locKey, string configKey, string description, StatusAttribute attribute, bool defaultValue = true)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			LocKey = locKey;
			ConfigKey = configKey;
			Description = description;
			this.attribute = attribute;
			this.defaultValue = defaultValue;
		}

		internal override void Bind(string category)
		{
			Cfg = ValConfig.BindServerConfig(category, ConfigKey, defaultValue, Description);
		}

		internal override void Apply(PassiveBuild build)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			SE_Stats se = build.Se;
			((StatusEffect)se).m_attributes = (StatusAttribute)(((StatusEffect)se).m_attributes | attribute);
		}

		internal override string ValueText()
		{
			return "";
		}
	}
	internal static class PowerTooltips
	{
		private const string LockedColor = "#808080";

		internal static BossPower Match(string statusEffectName)
		{
			if (string.IsNullOrEmpty(statusEffectName))
			{
				return null;
			}
			BossPower[] all = PowerDefinitions.All;
			foreach (BossPower bossPower in all)
			{
				if (statusEffectName == bossPower.PowerName || statusEffectName == bossPower.PassiveName)
				{
					return bossPower;
				}
			}
			return null;
		}

		internal static string Build(BossPower power)
		{
			int level = LevelRequirements.GetLevel(power);
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("<color=orange>").Append(Localize("$pp_level").Replace("$1", level.ToString()).Replace("$2", 7.ToString())).Append("</color>\n");
			bool value = ValConfig.ShowLockedFeatures.Value;
			for (int i = 0; i < power.Features.Length; i++)
			{
				PowerFeature powerFeature = power.Features[i];
				if (!powerFeature.Enabled)
				{
					continue;
				}
				if (level >= i + 1)
				{
					stringBuilder.Append('\n').Append(powerFeature.Describe());
				}
				else if (value)
				{
					stringBuilder.Append("\n<color=").Append("#808080").Append('>')
						.Append(powerFeature.Describe());
					string text = DescribeOutstanding(power, i + 1);
					if (text.Length > 0)
					{
						stringBuilder.Append("  ").Append(text);
					}
					stringBuilder.Append("</color>");
				}
			}
			return stringBuilder.ToString();
		}

		private static string DescribeOutstanding(BossPower power, int level)
		{
			Dictionary<string, int> dictionary = LevelRequirements.Outstanding(power, level);
			if (dictionary.Count == 0)
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder();
			foreach (KeyValuePair<string, int> item in dictionary)
			{
				if (stringBuilder.Length > 0)
				{
					stringBuilder.Append(", ");
				}
				BossPower bossPower = PowerDefinitions.ByYamlName(item.Key);
				stringBuilder.Append((bossPower != null) ? Localize(bossPower.LocKey) : item.Key).Append(" x").Append(item.Value);
			}
			return Localize("$pp_needs").Replace("$1", stringBuilder.ToString());
		}

		private static string Localize(string token)
		{
			if (Localization.instance == null)
			{
				return token;
			}
			return Localization.instance.Localize(token);
		}
	}
}
namespace ProgressivePowers.Common
{
	internal static class ConfigChangeDebouncer
	{
		private static readonly Dictionary<object, Action> pendingActions = new Dictionary<object, Action>();

		private static readonly Dictionary<object, float> fireAt = new Dictionary<object, float>();

		private static readonly HashSet<object> running = new HashSet<object>();

		internal static void Schedule(object key, Action action)
		{
			float num = ((ValConfig.ConfigApplyDelay != null) ? ValConfig.ConfigApplyDelay.Value : 0f);
			if (num <= 0f)
			{
				action();
				return;
			}
			ThreadingHelper instance = ThreadingHelper.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				pendingActions[key] = action;
				fireAt[key] = Time.realtimeSinceStartup + num;
				if (!running.Contains(key))
				{
					running.Add(key);
					((MonoBehaviour)instance).StartCoroutine(Run(key));
				}
			}
		}

		private static IEnumerator Run(object key)
		{
			float value;
			while (fireAt.TryGetValue(key, out value) && Time.realtimeSinceStartup < value)
			{
				yield return null;
			}
			pendingActions.TryGetValue(key, out var value2);
			pendingActions.Remove(key);
			fireAt.Remove(key);
			running.Remove(key);
			value2?.Invoke();
		}
	}
	internal static class ConfigDrawHelpers
	{
		private static readonly Dictionary<object, string> TextBuffer = new Dictionary<object, string>();

		private static readonly Dictionary<object, float> SliderPending = new Dictionary<object, float>();

		private static GUIStyle _headerButton;

		private static GUIStyle _groupLabel;

		private static GUIStyle _dim;

		internal static GUIStyle HeaderButton => _headerButton;

		internal static GUIStyle Dim => _dim;

		internal static void EnsureStyles()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			if (_headerButton == null)
			{
				_headerButton = new GUIStyle(GUI.skin.button)
				{
					alignment = (TextAnchor)3,
					fontStyle = (FontStyle)1
				};
				_groupLabel = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)1
				};
				_dim = new GUIStyle(GUI.skin.label)
				{
					fontStyle = (FontStyle)2,
					fontSize = 11
				};
			}
		}

		internal static ConfigurationManagerAttributes GetAttributes(ConfigEntryBase entry)
		{
			if (entry == null)
			{
				return null;
			}
			ConfigDescription description = entry.Description;
			if (description == null)
			{
				return null;
			}
			return description.Tags?.OfType<ConfigurationManagerAttributes>().FirstOrDefault();
		}

		internal static void Hide(ConfigEntryBase entry)
		{
			ConfigurationManagerAttributes attributes = GetAttributes(entry);
			if (attributes != null)
			{
				attributes.Browsable = false;
			}
		}

		internal static void GroupHeader(string text)
		{
			GUILayout.Space(4f);
			GUILayout.Label(text, _groupLabel, Array.Empty<GUILayoutOption>());
		}

		private static bool EnterPressed()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Invalid comparison between Unknown and I4
			if ((int)Event.current.type == 4)
			{
				if ((int)Event.current.keyCode != 13)
				{
					return (int)Event.current.keyCode == 271;
				}
				return true;
			}
			return false;
		}

		internal static void DrawBool(string label, ConfigEntry<bool> cfg)
		{
			bool flag = GUILayout.Toggle(cfg.Value, " " + label, Array.Empty<GUILayoutOption>());
			if (flag != cfg.Value)
			{
				cfg.Value = flag;
			}
		}

		internal static void DrawString(string label, ConfigEntry<string> cfg)
		{
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(230f) });
			string text = "str_" + ((object)cfg).GetHashCode();
			GUI.SetNextControlName(text);
			bool flag = GUI.GetNameOfFocusedControl() == text;
			string value;
			string text2 = GUILayout.TextField((flag && TextBuffer.TryGetValue(cfg, out value)) ? value : cfg.Value, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(230f) });
			string value2;
			if (flag)
			{
				TextBuffer[cfg] = text2;
				if (EnterPressed() && cfg.Value != text2)
				{
					cfg.Value = text2;
				}
			}
			else if (TextBuffer.TryGetValue(cfg, out value2))
			{
				if (cfg.Value != value2)
				{
					cfg.Value = value2;
				}
				TextBuffer.Remove(cfg);
			}
			GUILayout.EndHorizontal();
		}

		internal static void DrawChoice(string label, ConfigEntry<string> cfg)
		{
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(230f) });
			if (((ConfigEntryBase)cfg).Description.AcceptableValues is AcceptableValueList<string> val && val.AcceptableValues.Length != 0)
			{
				string[] acceptableValues = val.AcceptableValues;
				int num = Array.IndexOf(acceptableValues, cfg.Value);
				if (num < 0)
				{
					num = 0;
				}
				if (GUILayout.Button("◄", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(26f) }))
				{
					cfg.Value = acceptableValues[(num - 1 + acceptableValues.Length) % acceptableValues.Length];
				}
				GUILayout.Label(cfg.Value, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(160f) });
				if (GUILayout.Button("►", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(26f) }))
				{
					cfg.Value = acceptableValues[(num + 1) % acceptableValues.Length];
				}
			}
			else
			{
				GUILayout.Label(cfg.Value, Array.Empty<GUILayoutOption>());
			}
			GUILayout.EndHorizontal();
		}

		internal static void DrawFloat(string label, ConfigEntry<float> cfg)
		{
			float num = 0f;
			float num2 = Mathf.Max(100f, cfg.Value);
			if (((ConfigEntryBase)cfg).Description.AcceptableValues is AcceptableValueRange<float> val)
			{
				num = val.MinValue;
				num2 = val.MaxValue;
			}
			float num3 = DrawSliderRow(label, cfg, cfg.Value, num, num2, isInt: false);
			if (num3 != cfg.Value)
			{
				cfg.Value = Mathf.Clamp(num3, num, num2);
			}
		}

		internal static void DrawInt(string label, ConfigEntry<int> cfg)
		{
			float num = 0f;
			float num2 = Mathf.Max(100f, (float)cfg.Value);
			if (((ConfigEntryBase)cfg).Description.AcceptableValues is AcceptableValueRange<int> val)
			{
				num = val.MinValue;
				num2 = val.MaxValue;
			}
			int num3 = Mathf.Clamp(Mathf.RoundToInt(DrawSliderRow(label, cfg, cfg.Value, num, num2, isInt: true)), (int)num, (int)num2);
			if (num3 != cfg.Value)
			{
				cfg.Value = num3;
			}
		}

		private static float DrawSliderRow(string label, object key, float current, float min, float max, bool isInt)
		{
			float num = current;
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label(label, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(230f) });
			float value;
			float num2 = (SliderPending.TryGetValue(key, out value) ? value : current);
			float num3 = GUILayout.HorizontalSlider(num2, min, max, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) });
			if (Mathf.Abs(num3 - num2) > Mathf.Epsilon)
			{
				SliderPending[key] = num3;
			}
			if (SliderPending.TryGetValue(key, out var value2))
			{
				num = value2;
				if (!Input.GetMouseButton(0))
				{
					SliderPending.Remove(key);
				}
			}
			string text = "num_" + key.GetHashCode();
			GUI.SetNextControlName(text);
			bool flag = GUI.GetNameOfFocusedControl() == text;
			string text2 = (isInt ? Mathf.RoundToInt(num).ToString() : num.ToString("0.###"));
			string value3;
			string text3 = GUILayout.TextField((flag && TextBuffer.TryGetValue(key, out value3)) ? value3 : text2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
			string value4;
			if (flag)
			{
				TextBuffer[key] = text3;
				if (EnterPressed() && float.TryParse(text3, out var result))
				{
					num = result;
				}
			}
			else if (TextBuffer.TryGetValue(key, out value4))
			{
				if (float.TryParse(value4, out var result2))
				{
					num = result2;
				}
				TextBuffer.Remove(key);
			}
			GUILayout.Label("[" + (isInt ? min.ToString() : min.ToString("0.#")) + " - " + (isInt ? max.ToString() : max.ToString("0.#")) + "]", _dim, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(90f) });
			GUILayout.EndHorizontal();
			return num;
		}
	}
	internal static class LocalizationLoader
	{
		internal static string LocalizationFolder = "Localizations";

		internal static void AddLocalizations()
		{
			CustomLocalization localization = ProgressivePowers.Localization;
			string text = Path.Combine(Paths.ConfigPath, "ProgressivePowers", LocalizationFolder);
			Directory.CreateDirectory(text);
			string[] manifestResourceNames = Assembly.GetExecutingAssembly().GetManifestResourceNames();
			foreach (string text2 in manifestResourceNames)
			{
				if (!text2.Contains(LocalizationFolder))
				{
					continue;
				}
				string text3 = Regex.Replace(ReadEmbeddedResourceFile(text2), "\\/\\/.*", "");
				Dictionary<string, string> internal_localization = SimpleJson.DeserializeObject<Dictionary<string, string>>(text3);
				string[] array = text2.Split(new char[1] { '.' });
				if (File.Exists(text + "/" + array[2] + ".json"))
				{
					string text4 = File.ReadAllText(text + "/" + array[2] + ".json");
					try
					{
						Dictionary<string, string> dictionary = SimpleJson.DeserializeObject<Dictionary<string, string>>(text4);
						UpdateLocalizationWithMissingKeys(internal_localization, dictionary);
						Logger.LogDebug("Reading " + text + "/" + array[2] + ".json");
						File.WriteAllText(text + "/" + array[2] + ".json", SimpleJson.SerializeObject((object)dictionary));
						string text5 = File.ReadAllText(text + "/" + array[2] + ".json");
						localization.AddJsonFile(array[2], text5);
					}
					catch
					{
						File.WriteAllText(text + "/" + array[2] + ".json", text3);
						Logger.LogDebug("Reading " + text2);
						localization.AddJsonFile(array[2], text3);
					}
				}
				else
				{
					File.WriteAllText(text + "/" + array[2] + ".json", text3);
					Logger.LogDebug("Reading " + text2);
					localization.AddJsonFile(array[2], text3);
				}
				Logger.LogDebug("Added localization: '" + array[2] + "'");
			}
		}

		private static Dictionary<string, string> UpdateLocalizationWithMissingKeys(Dictionary<string, string> internal_localization, Dictionary<string, string> cached_localization)
		{
			if (internal_localization.Keys != cached_localization.Keys)
			{
				List<string> list = cached_localization.Keys.ToList();
				foreach (KeyValuePair<string, string> item in internal_localization)
				{
					list.Remove(item.Key);
					if (!cached_localization.ContainsKey(item.Key))
					{
						Logger.LogDebug("Adding missing localization key " + item.Key);
						cached_localization.Add(item.Key, item.Value);
					}
				}
				if (list.Count > 0)
				{
					Logger.LogDebug("Removing extra keys " + string.Join(",", list) + ".");
					foreach (string item2 in list)
					{
						cached_localization.Remove(item2);
					}
				}
			}
			return cached_localization;
		}

		private static string ReadEmbeddedResourceFile(string filename)
		{
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(filename);
			using StreamReader streamReader = new StreamReader(stream);
			return streamReader.ReadToEnd();
		}
	}
}