Decompiled source of Empress Achievements v1.2.0

RepoAchievements.dll

Decompiled 4 days 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.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("Omniscye")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+79ae26948f15ddd0825c08f9c67eab7df2c0586c")]
[assembly: AssemblyProduct("RepoAchievements")]
[assembly: AssemblyTitle("RepoAchievements")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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;
		}
	}
}
namespace RepoAchievements
{
	[BepInPlugin("Omniscye.RepoAchievements", "RepoAchievements", "1.0")]
	public class RepoAchievements : BaseUnityPlugin
	{
		internal static RepoAchievements Instance { get; private set; }

		internal static ManualLogSource Logger => Instance._logger;

		private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger;

		internal Harmony? Harmony { get; set; }

		private void Awake()
		{
			Instance = this;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			Patch();
			Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} has loaded!");
		}

		internal void Patch()
		{
			//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_0021: Expected O, but got Unknown
			//IL_0026: Expected O, but got Unknown
			if (Harmony == null)
			{
				Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
				Harmony val2 = val;
				Harmony = val;
			}
			Harmony.PatchAll();
		}

		internal void Unpatch()
		{
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void Update()
		{
		}
	}
}
namespace Empress.REPO.Achievements
{
	[HarmonyPatch]
	internal static class EmpressAchievementsPlus
	{
		private const float KillSpreeWindowSeconds = 10f;

		private const int KillSpreeCount = 5;

		private static readonly Queue<float> _killTimestamps = new Queue<float>();

		private static bool _defined;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(AchievementBook), "DefineDefaults")]
		private static void Post_DefineDefaults_AddMore()
		{
			if (!_defined)
			{
				_defined = true;
				Define("ach_meta_10", "Warmed Up", "Unlock 10 achievements.");
				Define("ach_meta_25", "On Your Way", "Unlock 25 achievements.");
				Define("ach_meta_50", "Certified Collector", "Unlock 50 achievements.");
				Define("ach_meta_75", "Overachiever", "Unlock 75 achievements.");
				Define("discover_10", "Curio Finder", "Discover 10 valuables.");
				Define("discover_25", "Antiquarian", "Discover 25 valuables.");
				Define("discover_50", "Treasure Sleuth", "Discover 50 valuables.");
				Define("discover_100", "Museum Curator", "Discover 100 valuables.");
				Define("run_kills_25", "Bloody Hands", "Eliminate 25 enemies in a single run.");
				Define("run_kills_50", "Crowd Control", "Eliminate 50 enemies in a single run.");
				Define("run_kills_100", "Neighborhood Watch", "Eliminate 100 enemies in a single run.");
				Define("kill_spree_5_10s", "Quick Hands", $"Eliminate {5} enemies within {10f:0} seconds.");
				Define("charge_session_1", "Juiced", "Start charging at a station.");
				Define("charge_session_10", "Power User", "Start charging at stations 10 times.");
				Define("charge_session_25", "Grid Hog", "Start charging at stations 25 times.");
				Define("charge_total_100", "Watt About It", "Accumulate 100 total station charge in a run.");
				Define("charge_total_500", "Peak Demand", "Accumulate 500 total station charge in a run.");
				Define("charge_total_1000", "Brownout", "Accumulate 1,000 total station charge in a run.");
				Define("run_purchases_10", "Shopaholic (Run)", "Buy 10 items in a single run.");
				Define("run_purchases_25", "Retail Bender", "Buy 25 items in a single run.");
				Define("no_purchase_run", "Barebones", "Extract without buying anything that run.");
				Define("run_money_150000", "High Roller", "Reach 150,000 run currency.");
				Define("run_money_250000", "Mega Whale", "Reach 250,000 run currency.");
				Define("run_money_500000", "Infinite Wallet", "Reach 500,000 run currency.");
				Define("run_level_5", "Warm Depths", "Reach level 5 in a run.");
				Define("run_level_10", "Deep Delver", "Reach level 10 in a run.");
				Define("run_level_15", "Abyss Dweller", "Reach level 15 in a run.");
				Define("nodeath_streak_2", "Back-to-Back", "Extract deathless twice in a row.");
				Define("nodeath_streak_5", "On Fire", "Extract deathless 5 times in a row.");
				Define("nodeath_streak_10", "Untouchable++", "Extract deathless 10 times in a row.");
				Define("kill_type_VeryLight_100", "Snack Extinction", "Eliminate 100 Very Light enemies.");
				Define("kill_type_Light_100", "Light's Out", "Eliminate 100 Light enemies.");
				Define("kill_type_Medium_100", "Middle Management Axed", "Eliminate 100 Medium enemies.");
				Define("kill_type_Heavy_100", "Heavy Industry", "Eliminate 100 Heavy enemies.");
				Define("kill_type_VeryHeavy_100", "Gravitational Collapse", "Eliminate 100 Very Heavy enemies.");
				Define("deaths_run_5", "Learning Hurts", "Die 5 times in a single run.");
				Define("deaths_run_10", "Pain Enthusiast", "Die 10 times in a single run.");
				Define("deaths_run_20", "Certified Masochist", "Die 20 times in a single run.");
				Define("kills_10000", "Bureau of Population", "Eliminate 10,000 enemies.");
				ManualLogSource log = EmpressAchievementsPlugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("[ACH+] Extra definitions loaded: " + AchievementBook.All.Count));
				}
			}
		}

		private static void Define(string id, string title, string desc)
		{
			AchievementBook.All[id] = new AchievementDef(id, title, desc);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(RoundDirector), "StartRoundRPC")]
		private static void Post_RoundStart_ResetPerRun()
		{
			ResetRunCounter("kills_run");
			ResetRunCounter("run_purchases");
			_killTimestamps.Clear();
		}

		private static void ResetRunCounter(string key)
		{
			long counter = EmpressAchievementsPlugin.Store.GetCounter(key);
			if (counter != 0)
			{
				EmpressAchievementsPlugin.Store.AddToCounter(key, -counter);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ValuableObject), "DiscoverRPC")]
		private static void Post_Discover_Bump()
		{
			EmpressAchievementsPlugin.Store.AddToCounter("discoveries", 1L);
			long counter = EmpressAchievementsPlugin.Store.GetCounter("discoveries");
			if (counter >= 10)
			{
				EmpressAchievementsPlugin.Unlock("discover_10");
			}
			if (counter >= 25)
			{
				EmpressAchievementsPlugin.Unlock("discover_25");
			}
			if (counter >= 50)
			{
				EmpressAchievementsPlugin.Unlock("discover_50");
			}
			if (counter >= 100)
			{
				EmpressAchievementsPlugin.Unlock("discover_100");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(StatsManager), "ItemPurchase")]
		private static void Post_ItemPurchase_RunCounter()
		{
			EmpressAchievementsPlugin.Store.AddToCounter("run_purchases", 1L);
			long counter = EmpressAchievementsPlugin.Store.GetCounter("run_purchases");
			if (counter >= 10)
			{
				EmpressAchievementsPlugin.Unlock("run_purchases_10");
			}
			if (counter >= 25)
			{
				EmpressAchievementsPlugin.Unlock("run_purchases_25");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ChargingStation), "StartChargeRPC")]
		private static void Post_Charge_Start()
		{
			EmpressAchievementsPlugin.Store.AddToCounter("charge_sessions", 1L);
			long counter = EmpressAchievementsPlugin.Store.GetCounter("charge_sessions");
			if (counter >= 1)
			{
				EmpressAchievementsPlugin.Unlock("charge_session_1");
			}
			if (counter >= 10)
			{
				EmpressAchievementsPlugin.Unlock("charge_session_10");
			}
			if (counter >= 25)
			{
				EmpressAchievementsPlugin.Unlock("charge_session_25");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PunManager), "SetRunStatSet")]
		private static void Post_RunStatSet(string statName, int value)
		{
			if (string.Equals(statName, "currency", StringComparison.OrdinalIgnoreCase))
			{
				if (value >= 150000)
				{
					EmpressAchievementsPlugin.Unlock("run_money_150000");
				}
				if (value >= 250000)
				{
					EmpressAchievementsPlugin.Unlock("run_money_250000");
				}
				if (value >= 500000)
				{
					EmpressAchievementsPlugin.Unlock("run_money_500000");
				}
			}
			else if (string.Equals(statName, "level", StringComparison.OrdinalIgnoreCase))
			{
				if (value >= 5)
				{
					EmpressAchievementsPlugin.Unlock("run_level_5");
				}
				if (value >= 10)
				{
					EmpressAchievementsPlugin.Unlock("run_level_10");
				}
				if (value >= 15)
				{
					EmpressAchievementsPlugin.Unlock("run_level_15");
				}
			}
			else if (string.Equals(statName, "chargingStationChargeTotal", StringComparison.OrdinalIgnoreCase))
			{
				if (value >= 100)
				{
					EmpressAchievementsPlugin.Unlock("charge_total_100");
				}
				if (value >= 500)
				{
					EmpressAchievementsPlugin.Unlock("charge_total_500");
				}
				if (value >= 1000)
				{
					EmpressAchievementsPlugin.Unlock("charge_total_1000");
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(RoundDirector), "ExtractionCompleted")]
		private static void Post_ExtractionCompleted_ExtraChecks()
		{
			long counter = EmpressAchievementsPlugin.Store.GetCounter("run_purchases");
			if (counter == 0)
			{
				EmpressAchievementsPlugin.Unlock("no_purchase_run");
			}
			if (EmpressAchievementsPlugin.GetStat("run_deaths") == 0)
			{
				long num = EmpressAchievementsPlugin.Store.GetCounter("nodeath_streak") + 1;
				EmpressAchievementsPlugin.Store.SetCounter("nodeath_streak", num);
				if (num >= 2)
				{
					EmpressAchievementsPlugin.Unlock("nodeath_streak_2");
				}
				if (num >= 5)
				{
					EmpressAchievementsPlugin.Unlock("nodeath_streak_5");
				}
				if (num >= 10)
				{
					EmpressAchievementsPlugin.Unlock("nodeath_streak_10");
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerAvatar), "PlayerDeathRPC")]
		private static void Post_PlayerDeath_ResetStreak()
		{
			EmpressAchievementsPlugin.Store.SetCounter("nodeath_streak", 0L);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(AchievementStore), "AddToCounter")]
		private static void Post_Store_AddToCounter(object __instance, string key, long delta)
		{
			AchievementStore achievementStore = (AchievementStore)__instance;
			if (string.Equals(key, "kills_total", StringComparison.OrdinalIgnoreCase) && delta > 0)
			{
				achievementStore.AddToCounter("kills_run", (int)delta);
				long counter = achievementStore.GetCounter("kills_run");
				if (counter >= 25)
				{
					EmpressAchievementsPlugin.Unlock("run_kills_25");
				}
				if (counter >= 50)
				{
					EmpressAchievementsPlugin.Unlock("run_kills_50");
				}
				if (counter >= 100)
				{
					EmpressAchievementsPlugin.Unlock("run_kills_100");
				}
				float unscaledTime = Time.unscaledTime;
				_killTimestamps.Enqueue(unscaledTime);
				while (_killTimestamps.Count > 0 && unscaledTime - _killTimestamps.Peek() > 10f)
				{
					_killTimestamps.Dequeue();
				}
				if (_killTimestamps.Count >= 5)
				{
					EmpressAchievementsPlugin.Unlock("kill_spree_5_10s");
				}
				long counter2 = achievementStore.GetCounter("kills_total");
				if (counter2 >= 10000)
				{
					EmpressAchievementsPlugin.Unlock("kills_10000");
				}
			}
			if (key.StartsWith("kills_type_", StringComparison.OrdinalIgnoreCase))
			{
				long counter3 = achievementStore.GetCounter(key);
				if (counter3 >= 100)
				{
					switch (key.Substring("kills_type_".Length))
					{
					case "VeryLight":
						EmpressAchievementsPlugin.Unlock("kill_type_VeryLight_100");
						break;
					case "Light":
						EmpressAchievementsPlugin.Unlock("kill_type_Light_100");
						break;
					case "Medium":
						EmpressAchievementsPlugin.Unlock("kill_type_Medium_100");
						break;
					case "Heavy":
						EmpressAchievementsPlugin.Unlock("kill_type_Heavy_100");
						break;
					case "VeryHeavy":
						EmpressAchievementsPlugin.Unlock("kill_type_VeryHeavy_100");
						break;
					}
				}
			}
			if (string.Equals(key, "run_deaths", StringComparison.OrdinalIgnoreCase) && delta > 0)
			{
				long counter4 = achievementStore.GetCounter("run_deaths");
				if (counter4 >= 5)
				{
					EmpressAchievementsPlugin.Unlock("deaths_run_5");
				}
				if (counter4 >= 10)
				{
					EmpressAchievementsPlugin.Unlock("deaths_run_10");
				}
				if (counter4 >= 20)
				{
					EmpressAchievementsPlugin.Unlock("deaths_run_20");
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(AchievementStore), "Unlock")]
		private static void Post_Store_Unlock_Milestones(AchievementStore __instance, string id)
		{
			AchievementStore __instance2 = __instance;
			try
			{
				int num = AchievementBook.All.Keys.Count((string k) => __instance2.IsUnlocked(k));
				if (num >= 10)
				{
					EmpressAchievementsPlugin.Unlock("ach_meta_10");
				}
				if (num >= 25)
				{
					EmpressAchievementsPlugin.Unlock("ach_meta_25");
				}
				if (num >= 50)
				{
					EmpressAchievementsPlugin.Unlock("ach_meta_50");
				}
				if (num >= 75)
				{
					EmpressAchievementsPlugin.Unlock("ach_meta_75");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = EmpressAchievementsPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[ACH+] Meta unlock check failed: " + ex));
				}
			}
		}
	}
	[BepInPlugin("empress.repo.achievements", "Empress Achievements", "1.3.8")]
	public class EmpressAchievementsPlugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private sealed class <InitializeUICoroutine>d__21 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public EmpressAchievementsPlugin <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <InitializeUICoroutine>d__21(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if (<>4__this.InitializeUIComponents())
					{
						((MonoBehaviour)<>4__this).StartCoroutine(Toast.LoadSoundCoroutine());
					}
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public const string PluginGuid = "empress.repo.achievements";

		public const string PluginName = "Empress Achievements";

		public const string PluginVersion = "1.3.8";

		private Harmony _harmony;

		internal static ConfigEntry<KeyCode> ToggleUiKey;

		internal static ConfigEntry<bool> EnableSound;

		internal static ConfigEntry<string> SoundFileName;

		internal static ConfigEntry<float> SoundVolume;

		internal static ConfigEntry<float> floatToastSeconds;

		internal static ConfigEntry<int> UiScalePercent;

		internal static ConfigEntry<bool> DebugLogJsonPreview;

		internal static ManualLogSource Log;

		internal static EmpressAchievementsPlugin Instance;

		internal static ToastUi Toast;

		internal static AchievementsUi AchievementsPanel;

		internal static AchievementStore Store;

		internal static bool TalliedExtractionThisRound = false;

		internal static float LastLocalDeathTime = -999f;

		internal static float LastPurchaseTime = -999f;

		internal static HashSet<int> ProcessedKillHashes = new HashSet<int>();

		private void Awake()
		{
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ToggleUiKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("UI", "ToggleKey", (KeyCode)289, "Key to open/close achievements panel");
			UiScalePercent = ((BaseUnityPlugin)this).Config.Bind<int>("UI", "UiScalePercent", 100, "UI scale percentage (100=default)");
			floatToastSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "ToastSeconds", 4f, "Seconds a toast stays visible");
			DebugLogJsonPreview = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogJsonPreview", false, "Log first ~300 chars of JSON after save.");
			EnableSound = ((BaseUnityPlugin)this).Config.Bind<bool>("Sound", "EnableSound", true, "Play a sound when an achievement pops");
			SoundFileName = ((BaseUnityPlugin)this).Config.Bind<string>("Sound", "SoundFileName", "empress_achievement.ogg", "Audio file placed next to the DLL (wav/ogg/mp3)");
			SoundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "Volume", 0.7f, "Toast sound volume (0-1)");
			string pluginFolder = Path.Combine(Paths.PluginPath, "Omniscye-Achievements");
			Store = new AchievementStore(pluginFolder, "empress_achievements.json");
			Log.LogInfo((object)("[ACH] Canonical save => " + Store.CanonicalFile));
			Store.Load();
			DumpFileMap("Boot");
			_harmony = new Harmony("empress.repo.achievements");
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			((MonoBehaviour)this).StartCoroutine(InitializeUICoroutine());
			AchievementBook.DefineDefaults();
			Log.LogInfo((object)("Empress Achievements v1.3.8 loaded. Achievements: " + AchievementBook.All.Count));
		}

		[IteratorStateMachine(typeof(<InitializeUICoroutine>d__21))]
		private IEnumerator InitializeUICoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <InitializeUICoroutine>d__21(0)
			{
				<>4__this = this
			};
		}

		private bool InitializeUIComponents()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			try
			{
				GameObject val = new GameObject("Empress_AchievementUI_Root");
				Object.DontDestroyOnLoad((Object)(object)val);
				Toast = val.AddComponent<ToastUi>();
				Toast.Duration = floatToastSeconds.Value;
				Toast.Volume = SoundVolume.Value;
				Toast.EnableSound = EnableSound.Value;
				string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
				Toast.SoundFilePath = (Path.IsPathRooted(SoundFileName.Value) ? SoundFileName.Value : Path.Combine(directoryName ?? Paths.PluginPath, SoundFileName.Value));
				if (!File.Exists(Toast.SoundFilePath))
				{
					string text = Path.Combine(Paths.PluginPath, "Omniscye-Achievements", SoundFileName.Value);
					if (File.Exists(text))
					{
						Toast.SoundFilePath = text;
					}
				}
				Toast.UiScale = (float)UiScalePercent.Value / 100f;
				AchievementsPanel = val.AddComponent<AchievementsUi>();
				AchievementsPanel.UiScale = Toast.UiScale;
				return true;
			}
			catch (Exception ex)
			{
				Log.LogError((object)("[ACH] UI init failed: " + ex));
				return false;
			}
		}

		private void OnDestroy()
		{
			try
			{
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch
			{
			}
			try
			{
				Store?.Save();
			}
			catch
			{
			}
		}

		private void OnApplicationQuit()
		{
			try
			{
				Store?.Save();
			}
			catch
			{
			}
		}

		private void Update()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(ToggleUiKey.Value) || Input.GetKeyDown((KeyCode)289))
			{
				AchievementsPanel?.Toggle();
			}
			if ((Object)(object)Toast != (Object)null)
			{
				Toast.Duration = floatToastSeconds.Value;
				Toast.Volume = SoundVolume.Value;
				Toast.EnableSound = EnableSound.Value;
				float num = (float)UiScalePercent.Value / 100f;
				if (Mathf.Abs(num - Toast.UiScale) > 0.001f)
				{
					Toast.UiScale = num;
					AchievementsPanel.UiScale = num;
					Toast.RefreshScale();
					AchievementsPanel.RefreshScale();
				}
			}
		}

		internal static void DumpFileMap(string tag)
		{
			try
			{
				string[] source = new string[3]
				{
					Path.Combine(Paths.ConfigPath, "EmpressAchievements", "empress_achievements.json"),
					Path.Combine(Paths.PluginPath, "Omniscye-Achievements", "empress_achievements.json"),
					Path.Combine(Paths.ConfigPath, "empress.repo.achievements.json")
				};
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogInfo((object)("[ACH][FileMap/" + tag + "] Scanning known locations:"));
				}
				foreach (string item in source.Distinct())
				{
					if (File.Exists(item))
					{
						FileInfo fileInfo = new FileInfo(item);
						ManualLogSource log2 = Log;
						if (log2 != null)
						{
							log2.LogInfo((object)$"[ACH][FileMap/{tag}] {item} | size={fileInfo.Length} | modified={fileInfo.LastWriteTimeUtc:O}");
						}
					}
					else
					{
						ManualLogSource log3 = Log;
						if (log3 != null)
						{
							log3.LogInfo((object)("[ACH][FileMap/" + tag + "] (missing) " + item));
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log4 = Log;
				if (log4 != null)
				{
					log4.LogWarning((object)("[ACH][FileMap] " + ex));
				}
			}
		}

		public static void Pop(string title, string body)
		{
			Toast?.Pop(title, body);
		}

		public static void Unlock(string id)
		{
			AchievementDef achievementDef = AchievementBook.Get(id);
			if (achievementDef != null && !Store.IsUnlocked(id))
			{
				Store.Unlock(id);
				Pop(achievementDef.Title, achievementDef.Description);
				AchievementsPanel?.RefreshAllIfOpen();
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogInfo((object)("[ACH] Unlocked: " + achievementDef.Id + " - " + achievementDef.Title));
				}
				Store.Save();
			}
		}

		public static void BumpStat(string key, int delta = 1)
		{
			Store.AddToCounter(key, delta);
			AchievementsPanel?.RefreshStatsIfOpen();
		}

		public static int GetStat(string key)
		{
			return (int)Store.GetCounter(key);
		}

		internal static string FormatK(long value)
		{
			long num = Math.Abs(value);
			if (num >= 1000)
			{
				float num2 = (float)value / 1000f;
				string text = ((Mathf.Abs(num2 - Mathf.Round(num2)) < 0.05f) ? num2.ToString("0") : num2.ToString("0.#"));
				return text + "K";
			}
			return value.ToString("N0");
		}
	}
	[Serializable]
	public class AchievementState
	{
		public string Id;

		public bool Unlocked;

		public int UnlockedAtUnix;
	}
	[Serializable]
	public class CounterKV
	{
		public string Key;

		public int Value;
	}
	[Serializable]
	public class AchievementsSave
	{
		public List<AchievementState> Achievements = new List<AchievementState>();

		public List<CounterKV> Counters = new List<CounterKV>();

		public int SchemaVersion = 2;
	}
	internal static class SaveJson
	{
		private static string Esc(string s)
		{
			if (s == null)
			{
				return "";
			}
			StringBuilder stringBuilder = new StringBuilder(s.Length + 8);
			foreach (char c in s)
			{
				switch (c)
				{
				case '"':
					stringBuilder.Append("\\\"");
					continue;
				case '\\':
					stringBuilder.Append("\\\\");
					continue;
				case '\b':
					stringBuilder.Append("\\b");
					continue;
				case '\f':
					stringBuilder.Append("\\f");
					continue;
				case '\n':
					stringBuilder.Append("\\n");
					continue;
				case '\r':
					stringBuilder.Append("\\r");
					continue;
				case '\t':
					stringBuilder.Append("\\t");
					continue;
				}
				if (c < ' ')
				{
					StringBuilder stringBuilder2 = stringBuilder.Append("\\u");
					int num = c;
					stringBuilder2.Append(num.ToString("x4"));
				}
				else
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}

		public static string Serialize(AchievementsSave data)
		{
			StringBuilder stringBuilder = new StringBuilder(Mathf.Max(1024, (data.Achievements.Count + data.Counters.Count) * 64));
			stringBuilder.Append("{\n  \"Achievements\": [");
			for (int i = 0; i < data.Achievements.Count; i++)
			{
				AchievementState achievementState = data.Achievements[i];
				if (i > 0)
				{
					stringBuilder.Append(',');
				}
				stringBuilder.Append("\n    {").Append("\"Id\":\"").Append(Esc(achievementState.Id ?? ""))
					.Append("\",")
					.Append("\"Unlocked\":")
					.Append(achievementState.Unlocked ? "true" : "false")
					.Append(',')
					.Append("\"UnlockedAtUnix\":")
					.Append(achievementState.UnlockedAtUnix)
					.Append('}');
			}
			stringBuilder.Append("\n  ],\n  \"Counters\": [");
			for (int j = 0; j < data.Counters.Count; j++)
			{
				CounterKV counterKV = data.Counters[j];
				if (j > 0)
				{
					stringBuilder.Append(',');
				}
				stringBuilder.Append("\n    {").Append("\"Key\":\"").Append(Esc(counterKV.Key ?? ""))
					.Append("\",")
					.Append("\"Value\":")
					.Append(counterKV.Value)
					.Append('}');
			}
			stringBuilder.Append("\n  ],\n  \"SchemaVersion\": ").Append(data.SchemaVersion).Append("\n}");
			return stringBuilder.ToString();
		}
	}
	internal static class LoadJsonFallback
	{
		private static bool ArrayLooksPopulated(string json, string key)
		{
			Regex regex = new Regex("\"" + Regex.Escape(key) + "\"\\s*:\\s*\\[\\s*\\{", RegexOptions.Singleline);
			return regex.IsMatch(json);
		}

		private static string ExtractArray(string json, string key)
		{
			int num = json.IndexOf("\"" + key + "\"", StringComparison.Ordinal);
			if (num < 0)
			{
				return null;
			}
			int num2 = json.IndexOf('[', num);
			if (num2 < 0)
			{
				return null;
			}
			int num3 = 0;
			for (int i = num2; i < json.Length; i++)
			{
				switch (json[i])
				{
				case '[':
					num3++;
					break;
				case ']':
					num3--;
					if (num3 == 0)
					{
						return json.Substring(num2, i - num2 + 1);
					}
					break;
				}
			}
			return null;
		}

		public static bool JsonIndicatesItems(string json, out bool hasA, out bool hasC)
		{
			hasA = ArrayLooksPopulated(json, "Achievements");
			hasC = ArrayLooksPopulated(json, "Counters");
			return hasA | hasC;
		}

		public static bool TryParse(string json, out AchievementsSave save)
		{
			save = new AchievementsSave();
			try
			{
				string text = ExtractArray(json, "Achievements");
				string text2 = ExtractArray(json, "Counters");
				if (!string.IsNullOrEmpty(text))
				{
					Regex regex = new Regex("\\{\\s*\"Id\"\\s*:\\s*\"(?<id>.*?)\"\\s*,\\s*\"Unlocked\"\\s*:\\s*(?<u>true|false)\\s*,\\s*\"UnlockedAtUnix\"\\s*:\\s*(?<t>-?\\d+)\\s*\\}", RegexOptions.Singleline);
					foreach (Match item in regex.Matches(text))
					{
						int result;
						AchievementState achievementState = new AchievementState
						{
							Id = item.Groups["id"].Value,
							Unlocked = (item.Groups["u"].Value == "true"),
							UnlockedAtUnix = (int.TryParse(item.Groups["t"].Value, out result) ? result : 0)
						};
						if (!string.IsNullOrEmpty(achievementState.Id))
						{
							save.Achievements.Add(achievementState);
						}
					}
				}
				if (!string.IsNullOrEmpty(text2))
				{
					Regex regex2 = new Regex("\\{\\s*\"Key\"\\s*:\\s*\"(?<k>.*?)\"\\s*,\\s*\"Value\"\\s*:\\s*(?<v>-?\\d+)\\s*\\}", RegexOptions.Singleline);
					foreach (Match item2 in regex2.Matches(text2))
					{
						int result2;
						CounterKV counterKV = new CounterKV
						{
							Key = item2.Groups["k"].Value,
							Value = (int.TryParse(item2.Groups["v"].Value, out result2) ? result2 : 0)
						};
						if (!string.IsNullOrEmpty(counterKV.Key))
						{
							save.Counters.Add(counterKV);
						}
					}
				}
				Regex regex3 = new Regex("\"SchemaVersion\"\\s*:\\s*(?<s>\\d+)");
				Match match3 = regex3.Match(json);
				if (match3.Success && int.TryParse(match3.Groups["s"].Value, out var result3))
				{
					save.SchemaVersion = result3;
				}
				return true;
			}
			catch
			{
				save = new AchievementsSave();
				return false;
			}
		}
	}
	public class AchievementStore
	{
		private readonly string _pluginFolder;

		private readonly string _pluginFile;

		private AchievementsSave _data = new AchievementsSave();

		private readonly Dictionary<string, long> _counters = new Dictionary<string, long>();

		public string CanonicalFolder => Path.Combine(Paths.ConfigPath, "EmpressAchievements");

		public string CanonicalFile => Path.Combine(CanonicalFolder, "empress_achievements.json");

		private string PluginOldFile => _pluginFile;

		private string LegacyConfigFile => Path.Combine(Paths.ConfigPath, "empress.repo.achievements.json");

		public AchievementStore(string pluginFolder, string filename)
		{
			_pluginFolder = pluginFolder;
			_pluginFile = Path.Combine(pluginFolder, filename);
		}

		public bool IsUnlocked(string id)
		{
			string id2 = id;
			return _data.Achievements.Any((AchievementState a) => a.Id == id2 && a.Unlocked);
		}

		public long GetCounter(string key)
		{
			long value;
			return _counters.TryGetValue(key, out value) ? value : 0;
		}

		public void AddToCounter(string key, long delta)
		{
			if (!_counters.ContainsKey(key))
			{
				_counters[key] = 0L;
			}
			_counters[key] += delta;
			Save();
		}

		public void SetCounter(string key, long value)
		{
			_counters[key] = value;
			Save();
		}

		public void Unlock(string id)
		{
			string id2 = id;
			AchievementState achievementState = _data.Achievements.FirstOrDefault((AchievementState a) => a.Id == id2);
			if (achievementState == null)
			{
				achievementState = new AchievementState
				{
					Id = id2
				};
				_data.Achievements.Add(achievementState);
			}
			achievementState.Unlocked = true;
			long num = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
			achievementState.UnlockedAtUnix = (int)((num > int.MaxValue) ? int.MaxValue : num);
			Save();
		}

		public void Load()
		{
			try
			{
				EnsureCanonicalDir();
				List<string> list = new List<string>();
				if (File.Exists(CanonicalFile))
				{
					list.Add(CanonicalFile);
				}
				if (File.Exists(PluginOldFile))
				{
					list.Add(PluginOldFile);
				}
				if (File.Exists(LegacyConfigFile))
				{
					list.Add(LegacyConfigFile);
				}
				string text = ((list.Count > 0) ? list.OrderByDescending(SafeGetWriteTimeUtc).First() : null);
				if (text == null)
				{
					PersistCanonical(SaveJson.Serialize(_data), verify: true, "Fresh");
					ManualLogSource log = EmpressAchievementsPlugin.Log;
					if (log != null)
					{
						log.LogInfo((object)"[ACH] Created fresh save.");
					}
					return;
				}
				string text2 = File.ReadAllText(text, Encoding.UTF8);
				AchievementsSave achievementsSave = null;
				bool flag = false;
				try
				{
					if (!string.IsNullOrWhiteSpace(text2))
					{
						achievementsSave = JsonUtility.FromJson<AchievementsSave>(text2);
					}
				}
				catch
				{
					achievementsSave = null;
				}
				LoadJsonFallback.JsonIndicatesItems(text2, out var hasA, out var hasC);
				if ((achievementsSave == null || achievementsSave.Achievements == null || achievementsSave.Counters == null || (achievementsSave.Achievements != null && achievementsSave.Achievements.Count == 0 && hasA) || (achievementsSave.Counters != null && achievementsSave.Counters.Count == 0 && hasC)) && LoadJsonFallback.TryParse(text2, out AchievementsSave save))
				{
					achievementsSave = save;
					flag = true;
				}
				if (achievementsSave != null)
				{
					_data = achievementsSave;
					AchievementsSave data = _data;
					if (data.Achievements == null)
					{
						data.Achievements = new List<AchievementState>();
					}
					data = _data;
					if (data.Counters == null)
					{
						data.Counters = new List<CounterKV>();
					}
					_counters.Clear();
					foreach (CounterKV counter in _data.Counters)
					{
						if (counter != null && !string.IsNullOrEmpty(counter.Key))
						{
							_counters[counter.Key] = counter.Value;
						}
					}
					bool flag2 = text != CanonicalFile;
					if (flag2 || flag)
					{
						PersistCanonical(SaveJson.Serialize(_data), verify: true, flag2 ? "Migrate" : "Normalize");
					}
					if (text != CanonicalFile)
					{
						TryDelete(text);
					}
					ManualLogSource log2 = EmpressAchievementsPlugin.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)("[ACH] Loaded save from: " + text));
					}
				}
				else
				{
					_data = new AchievementsSave();
					_counters.Clear();
					ManualLogSource log3 = EmpressAchievementsPlugin.Log;
					if (log3 != null)
					{
						log3.LogWarning((object)("[ACH] Load parse failed for " + text + ". Keeping file on disk unchanged; in-memory starts fresh."));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log4 = EmpressAchievementsPlugin.Log;
				if (log4 != null)
				{
					log4.LogWarning((object)("[ACH] Load exception: " + ex));
				}
				_data = new AchievementsSave();
				_counters.Clear();
			}
		}

		public void Save()
		{
			try
			{
				AchievementsSave data = _data;
				if (data.Achievements == null)
				{
					data.Achievements = new List<AchievementState>();
				}
				_data.Counters = _counters.Select<KeyValuePair<string, long>, CounterKV>((KeyValuePair<string, long> kv) => new CounterKV
				{
					Key = kv.Key,
					Value = (int)((kv.Value > int.MaxValue) ? int.MaxValue : ((kv.Value < int.MinValue) ? int.MinValue : kv.Value))
				}).ToList();
				if (_data.Achievements.Count == 0 && _data.Counters.Count == 0 && OnDiskLooksPopulated())
				{
					ManualLogSource log = EmpressAchievementsPlugin.Log;
					if (log != null)
					{
						log.LogWarning((object)"[ACH] Save skipped to avoid clobber: memory is empty but disk has items.");
					}
					return;
				}
				string text = SaveJson.Serialize(_data);
				PersistCanonical(text, verify: true, "Save");
				long num = _data.Achievements.Count;
				long num2 = _data.Counters.Count;
				long num3 = SafeGetLength(CanonicalFile);
				if ((Object)(object)EmpressAchievementsPlugin.Instance != (Object)null && EmpressAchievementsPlugin.DebugLogJsonPreview.Value)
				{
					string text2 = ((text.Length > 300) ? (text.Substring(0, 300) + "...") : text);
					ManualLogSource log2 = EmpressAchievementsPlugin.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)("[ACH] JSON preview: " + text2.Replace("\n", "\\n")));
					}
				}
				ManualLogSource log3 = EmpressAchievementsPlugin.Log;
				if (log3 != null)
				{
					log3.LogInfo((object)$"[ACH] Saved {num} achievements, {num2} counters -> {CanonicalFile} ({num3} bytes) [verify OK]");
				}
				EmpressAchievementsPlugin.DumpFileMap("AfterSave");
			}
			catch (Exception ex)
			{
				ManualLogSource log4 = EmpressAchievementsPlugin.Log;
				if (log4 != null)
				{
					log4.LogWarning((object)("[ACH] Save failed: " + ex));
				}
			}
		}

		private bool OnDiskLooksPopulated()
		{
			try
			{
				if (!File.Exists(CanonicalFile))
				{
					return false;
				}
				string json = File.ReadAllText(CanonicalFile, Encoding.UTF8);
				bool hasA;
				bool hasC;
				return LoadJsonFallback.JsonIndicatesItems(json, out hasA, out hasC) && (hasA || hasC);
			}
			catch
			{
				return false;
			}
		}

		private void EnsureCanonicalDir()
		{
			try
			{
				Directory.CreateDirectory(CanonicalFolder);
			}
			catch
			{
			}
		}

		private void PersistCanonical(string json, bool verify, string context)
		{
			EnsureCanonicalDir();
			string text = CanonicalFile + ".tmp";
			try
			{
				using FileStream fileStream = new FileStream(text, FileMode.Create, FileAccess.Write, FileShare.None, 4096, FileOptions.WriteThrough);
				using StreamWriter streamWriter = new StreamWriter(fileStream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
				streamWriter.Write(json);
				streamWriter.Flush();
				fileStream.Flush(flushToDisk: true);
			}
			catch (Exception arg)
			{
				ManualLogSource log = EmpressAchievementsPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)$"[ACH] {context} tmp write failed: {arg}");
				}
				throw;
			}
			try
			{
				if (File.Exists(CanonicalFile))
				{
					try
					{
						File.Replace(text, CanonicalFile, CanonicalFile + ".bak");
					}
					catch
					{
						try
						{
							File.Delete(CanonicalFile);
						}
						catch
						{
						}
						File.Move(text, CanonicalFile);
					}
				}
				else
				{
					File.Move(text, CanonicalFile);
				}
			}
			catch (Exception arg2)
			{
				ManualLogSource log2 = EmpressAchievementsPlugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)$"[ACH] {context} replace failed: {arg2}");
				}
				throw;
			}
			if (!verify)
			{
				return;
			}
			try
			{
				string text2 = File.ReadAllText(CanonicalFile, Encoding.UTF8);
				if (!string.Equals(text2, json, StringComparison.Ordinal))
				{
					string text3 = ((text2.Length > 300) ? (text2.Substring(0, 300) + "...") : text2);
					ManualLogSource log3 = EmpressAchievementsPlugin.Log;
					if (log3 != null)
					{
						log3.LogWarning((object)$"[ACH] VERIFY STRING MISMATCH after {context}: lenWritten={json.Length}, lenRead={text2.Length}");
					}
					ManualLogSource log4 = EmpressAchievementsPlugin.Log;
					if (log4 != null)
					{
						log4.LogWarning((object)("[ACH] On-disk head: " + text3.Replace("\n", "\\n")));
					}
				}
			}
			catch (Exception arg3)
			{
				ManualLogSource log5 = EmpressAchievementsPlugin.Log;
				if (log5 != null)
				{
					log5.LogWarning((object)$"[ACH] Verify read failed after {context}: {arg3}");
				}
			}
		}

		private static DateTime SafeGetWriteTimeUtc(string path)
		{
			try
			{
				return File.GetLastWriteTimeUtc(path);
			}
			catch
			{
				return DateTime.MinValue;
			}
		}

		private static long SafeGetLength(string path)
		{
			try
			{
				return new FileInfo(path).Length;
			}
			catch
			{
				return 0L;
			}
		}

		private static void TryDelete(string path)
		{
			try
			{
				if (File.Exists(path))
				{
					File.Delete(path);
				}
			}
			catch
			{
			}
		}
	}
	public class AchievementDef
	{
		public string Id;

		public string Title;

		public string Description;

		public AchievementDef(string id, string title, string description)
		{
			Id = id;
			Title = title;
			Description = description;
		}
	}
	public static class AchievementBook
	{
		public static readonly Dictionary<string, AchievementDef> All = new Dictionary<string, AchievementDef>();

		public static AchievementDef Get(string id)
		{
			AchievementDef value;
			return All.TryGetValue(id, out value) ? value : null;
		}

		public static IEnumerable<AchievementDef> AllOrdered()
		{
			return All.Values.OrderBy((AchievementDef d) => d.Title);
		}

		public static void DefineDefaults()
		{
			All.Clear();
			Add("first_extract", "First Extraction", "Complete any extraction.");
			Add("extract_5", "Commuter", "Complete 5 extractions (lifetime).");
			Add("extract_20", "Frequent Flyer", "Complete 20 extractions (lifetime).");
			Add("extract_50", "Shuttle Regular", "Complete 50 extractions (lifetime).");
			Add("extract_100", "Season Pass Holder", "Complete 100 extractions (lifetime).");
			Add("extract_200", "Lives Here Now", "Complete 200 extractions (lifetime).");
			Add("run_money_10000", "Cash Flash", "Reach 10,000 run currency.");
			Add("run_money_25000", "Bankroller", "Reach 25,000 run currency.");
			Add("run_money_50000", "Whale", "Reach 50,000 run currency.");
			Add("run_money_100000", "Making It Rain", "Reach 100,000 run currency.");
			Add("run_haul_10000", "Hauler", "Reach 10,000 haul value in a run.");
			Add("run_haul_25000", "Mover", "Reach 25,000 haul value in a run.");
			Add("run_haul_50000", "Freight Lord", "Reach 50,000 haul value in a run.");
			Add("life_haul_50k", "Thrifty Tycoon", "Accumulate 50,000 haul (lifetime).");
			Add("life_haul_100k", "Millionaire-ish", "Accumulate 100,000 haul (lifetime).");
			Add("life_haul_250k", "Quarter Mil", "Accumulate 250,000 haul (lifetime).");
			Add("life_haul_500k", "Half Ticket", "Accumulate 500,000 haul (lifetime).");
			Add("life_haul_1m", "Seven Figures", "Accumulate 1,000,000 haul (lifetime).");
			Add("life_haul_2m", "Eight-ish", "Accumulate 2,000,000 haul (lifetime).");
			Add("life_haul_5m", "Big Bags", "Accumulate 5,000,000 haul (lifetime).");
			Add("life_haul_10m", "Dragon Hoard", "Accumulate 10,000,000 haul (lifetime).");
			Add("life_haul_20m", "Vault Dweller", "Accumulate 20,000,000 haul (lifetime).");
			Add("life_haul_50m", "Scrooge McDuck", "Accumulate 50,000,000 haul (lifetime).");
			Add("first_purchase", "Window Shopper No More", "Purchase your first item.");
			Add("big_spender_10", "Bulk Buyer", "Purchase 10 items (lifetime).");
			Add("big_spender_25", "Cart Commander", "Purchase 25 items (lifetime).");
			Add("big_spender_50", "Mall Rat", "Purchase 50 items (lifetime).");
			Add("big_spender_100", "Retail Therapy", "Purchase 100 items (lifetime).");
			Add("first_death", "Oops", "Die for the first time.");
			Add("death_5", "Oops, I Did It Again", "Die 5 times.");
			Add("death_10", "Try, Try Again", "Die 10 times.");
			Add("death_20", "Professional Victim", "Die 20 times.");
			Add("death_30", "Speedrun to the Afterlife", "Die 30 times.");
			Add("death_40", "Grave Connoisseur", "Die 40 times.");
			Add("death_50", "Certified Floor Tester", "Die 50 times.");
			Add("death_100", "Immortal (In Theory)", "Die 100 times.");
			Add("death_200", "Groundhog Day", "Die 200 times.");
			Add("death_500", "The Floor Is My Home", "Die 500 times.");
			Add("revived", "Back On Your Feet", "Get revived.");
			Add("revived_10", "Serial Resurrectee", "Be revived 10 times.");
			Add("revived_50", "Phoenix Program", "Be revived 50 times.");
			Add("nodeath_run", "Untouchable", "Complete an extraction without dying.");
			Add("first_discover", "Treasure Hunter", "Discover your first valuable.");
			Add("kills_10", "First Bloodbath", "Eliminate 10 enemies.");
			Add("kills_50", "Pest Control", "Eliminate 50 enemies.");
			Add("kills_100", "Exterminator", "Eliminate 100 enemies.");
			Add("kills_250", "Reaper Intern", "Eliminate 250 enemies.");
			Add("kills_500", "Reaper Associate", "Eliminate 500 enemies.");
			Add("kills_1000", "Full-Time Reaper", "Eliminate 1,000 enemies.");
			Add("kills_2000", "Warfare Dept.", "Eliminate 2,000 enemies.");
			Add("kills_5000", "Population Control", "Eliminate 5,000 enemies.");
			Add("kill_type_VeryLight", "Light Snack", "Eliminate a Very Light enemy.");
			Add("kill_type_Light", "Featherweight Fighter", "Eliminate a Light enemy.");
			Add("kill_type_Medium", "Middle Management", "Eliminate a Medium enemy.");
			Add("kill_type_Heavy", "Heavy Metal", "Eliminate a Heavy enemy.");
			Add("kill_type_VeryHeavy", "Heaviest Hand", "Eliminate a Very Heavy enemy.");
			Add("kill_type_VeryLight_25", "Snack Attack", "Eliminate 25 Very Light enemies.");
			Add("kill_type_Light_25", "Light Work", "Eliminate 25 Light enemies.");
			Add("kill_type_Medium_25", "Middle Manager", "Eliminate 25 Medium enemies.");
			Add("kill_type_Heavy_25", "Heavy Lifter", "Eliminate 25 Heavy enemies.");
			Add("kill_type_VeryHeavy_25", "Atlas", "Eliminate 25 Very Heavy enemies.");
		}

		private static void Add(string id, string title, string desc)
		{
			All[id] = new AchievementDef(id, title, desc);
		}
	}
	internal class ToastMessage
	{
		public string Title;

		public string Body;

		public ToastMessage(string t, string b)
		{
			Title = t;
			Body = b;
		}
	}
	public class ToastUi : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <LoadSoundCoroutine>d__13 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public ToastUi <>4__this;

			private string <uri>5__1;

			private UnityWebRequest <req>5__2;

			private bool <ok>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadSoundCoroutine>d__13(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<uri>5__1 = null;
				<req>5__2 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0103: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>4__this.Ensure();
					<>4__this._clip = null;
					if (!<>4__this.EnableSound)
					{
						return false;
					}
					if (string.IsNullOrEmpty(<>4__this.SoundFilePath) || !File.Exists(<>4__this.SoundFilePath))
					{
						EmpressAchievementsPlugin.Log.LogInfo((object)("[ACH] No sound file at: " + (<>4__this.SoundFilePath ?? "null")));
						return false;
					}
					EmpressAchievementsPlugin.Log.LogInfo((object)("[ACH] Loading sound from: " + <>4__this.SoundFilePath));
					<uri>5__1 = "file://" + <>4__this.SoundFilePath.Replace("\\", "/");
					<req>5__2 = UnityWebRequestMultimedia.GetAudioClip(<uri>5__1, GetAudioType(<>4__this.SoundFilePath));
					<>2__current = <req>5__2.SendWebRequest();
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<ok>5__3 = !<req>5__2.isNetworkError && !<req>5__2.isHttpError;
					if (<ok>5__3)
					{
						<>4__this._clip = DownloadHandlerAudioClip.GetContent(<req>5__2);
					}
					else
					{
						ManualLogSource log = EmpressAchievementsPlugin.Log;
						if (log != null)
						{
							log.LogWarning((object)("[ACH] Audio load failed: " + <req>5__2.error));
						}
					}
					<req>5__2.Dispose();
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <Run>d__16 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public ToastUi <>4__this;

			private ToastMessage <msg>5__1;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Run>d__16(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<msg>5__1 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>4__this._busy = true;
					break;
				case 1:
					<>1__state = -1;
					<msg>5__1 = null;
					break;
				}
				if (<>4__this._queue.Count > 0)
				{
					<msg>5__1 = <>4__this._queue.Dequeue();
					<>2__current = <>4__this.ShowToast(<msg>5__1.Title, <msg>5__1.Body);
					<>1__state = 1;
					return true;
				}
				<>4__this._busy = false;
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <ShowToast>d__17 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string title;

			public string body;

			public ToastUi <>4__this;

			private GameObject <go>5__1;

			private RectTransform <rt>5__2;

			private Image <bg>5__3;

			private Outline <outline>5__4;

			private GameObject <titleGO>5__5;

			private RectTransform <titleRT>5__6;

			private TextMeshProUGUI <titleTMP>5__7;

			private GameObject <bodyGO>5__8;

			private RectTransform <bodyRT>5__9;

			private TextMeshProUGUI <bodyTMP>5__10;

			private float <usableWidth>5__11;

			private Vector2 <titlePref>5__12;

			private Vector2 <bodyPref>5__13;

			private float <newHeight>5__14;

			private float <t>5__15;

			private Vector2 <start>5__16;

			private Vector2 <mid>5__17;

			private Vector2 <end>5__18;

			private CanvasGroup <cg>5__19;

			private float <inDur>5__20;

			private float <outDur>5__21;

			private AudioSource <a>5__22;

			private float <p>5__23;

			private float <e>5__24;

			private float <p>5__25;

			private float <e>5__26;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ShowToast>d__17(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<go>5__1 = null;
				<rt>5__2 = null;
				<bg>5__3 = null;
				<outline>5__4 = null;
				<titleGO>5__5 = null;
				<titleRT>5__6 = null;
				<titleTMP>5__7 = null;
				<bodyGO>5__8 = null;
				<bodyRT>5__9 = null;
				<bodyTMP>5__10 = null;
				<cg>5__19 = null;
				<a>5__22 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_004a: Expected O, but got Unknown
				//IL_0083: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
				//IL_0117: Unknown result type (might be due to invalid IL or missing references)
				//IL_0128: Unknown result type (might be due to invalid IL or missing references)
				//IL_0132: Expected O, but got Unknown
				//IL_0166: Unknown result type (might be due to invalid IL or missing references)
				//IL_0181: Unknown result type (might be due to invalid IL or missing references)
				//IL_019c: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
				//IL_020b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0261: Unknown result type (might be due to invalid IL or missing references)
				//IL_026b: Expected O, but got Unknown
				//IL_029f: Unknown result type (might be due to invalid IL or missing references)
				//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
				//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
				//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_0344: Unknown result type (might be due to invalid IL or missing references)
				//IL_038e: Unknown result type (might be due to invalid IL or missing references)
				//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
				//IL_03c5: Unknown result type (might be due to invalid IL or missing references)
				//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
				//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
				//IL_042a: Unknown result type (might be due to invalid IL or missing references)
				//IL_043a: Unknown result type (might be due to invalid IL or missing references)
				//IL_045b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0460: Unknown result type (might be due to invalid IL or missing references)
				//IL_0470: Unknown result type (might be due to invalid IL or missing references)
				//IL_0475: Unknown result type (might be due to invalid IL or missing references)
				//IL_0485: Unknown result type (might be due to invalid IL or missing references)
				//IL_048a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0496: Unknown result type (might be due to invalid IL or missing references)
				//IL_05b5: Unknown result type (might be due to invalid IL or missing references)
				//IL_05bb: Unknown result type (might be due to invalid IL or missing references)
				//IL_05c6: Unknown result type (might be due to invalid IL or missing references)
				//IL_0616: Unknown result type (might be due to invalid IL or missing references)
				//IL_0637: Unknown result type (might be due to invalid IL or missing references)
				//IL_0641: Expected O, but got Unknown
				//IL_06c4: Unknown result type (might be due to invalid IL or missing references)
				//IL_06ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_06d5: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<go>5__1 = new GameObject("Toast");
					<rt>5__2 = <go>5__1.AddComponent<RectTransform>();
					((Transform)<rt>5__2).SetParent((Transform)(object)<>4__this._root, false);
					<rt>5__2.sizeDelta = new Vector2(520f, 100f);
					<bg>5__3 = <go>5__1.AddComponent<Image>();
					((Graphic)<bg>5__3).color = new Color(0.05f, 0.05f, 0.05f, 0.9f);
					((Graphic)<bg>5__3).raycastTarget = false;
					<outline>5__4 = <go>5__1.AddComponent<Outline>();
					((Shadow)<outline>5__4).effectDistance = new Vector2(2f, -2f);
					((Shadow)<outline>5__4).effectColor = new Color(0.9f, 0.7f, 0.2f, 0.85f);
					<titleGO>5__5 = new GameObject("Title");
					<titleRT>5__6 = <titleGO>5__5.AddComponent<RectTransform>();
					((Transform)<titleRT>5__6).SetParent((Transform)(object)<rt>5__2, false);
					<titleRT>5__6.anchorMin = new Vector2(0f, 0.5f);
					<titleRT>5__6.anchorMax = new Vector2(1f, 1f);
					<titleRT>5__6.offsetMin = new Vector2(15f, -5f);
					<titleRT>5__6.offsetMax = new Vector2(-15f, -5f);
					<titleTMP>5__7 = <titleGO>5__5.AddComponent<TextMeshProUGUI>();
					((TMP_Text)<titleTMP>5__7).text = title;
					((TMP_Text)<titleTMP>5__7).fontSize = 24f;
					((Graphic)<titleTMP>5__7).color = new Color(1f, 0.93f, 0.6f);
					((TMP_Text)<titleTMP>5__7).alignment = (TextAlignmentOptions)4097;
					((TMP_Text)<titleTMP>5__7).enableWordWrapping = true;
					((TMP_Text)<titleTMP>5__7).overflowMode = (TextOverflowModes)1;
					((TMP_Text)<titleTMP>5__7).fontStyle = (FontStyles)1;
					((Graphic)<titleTMP>5__7).raycastTarget = false;
					<bodyGO>5__8 = new GameObject("Body");
					<bodyRT>5__9 = <bodyGO>5__8.AddComponent<RectTransform>();
					((Transform)<bodyRT>5__9).SetParent((Transform)(object)<rt>5__2, false);
					<bodyRT>5__9.anchorMin = new Vector2(0f, 0f);
					<bodyRT>5__9.anchorMax = new Vector2(1f, 0.5f);
					<bodyRT>5__9.offsetMin = new Vector2(15f, 5f);
					<bodyRT>5__9.offsetMax = new Vector2(-15f, 5f);
					<bodyTMP>5__10 = <bodyGO>5__8.AddComponent<TextMeshProUGUI>();
					((TMP_Text)<bodyTMP>5__10).text = body;
					((TMP_Text)<bodyTMP>5__10).fontSize = 16f;
					((Graphic)<bodyTMP>5__10).color = new Color(0.9f, 0.9f, 0.9f);
					((TMP_Text)<bodyTMP>5__10).alignment = (TextAlignmentOptions)4097;
					((TMP_Text)<bodyTMP>5__10).enableWordWrapping = true;
					((TMP_Text)<bodyTMP>5__10).overflowMode = (TextOverflowModes)1;
					((Graphic)<bodyTMP>5__10).raycastTarget = false;
					<usableWidth>5__11 = <rt>5__2.sizeDelta.x - 30f;
					<titlePref>5__12 = ((TMP_Text)<titleTMP>5__7).GetPreferredValues(((TMP_Text)<titleTMP>5__7).text, <usableWidth>5__11, 0f);
					<bodyPref>5__13 = ((TMP_Text)<bodyTMP>5__10).GetPreferredValues(((TMP_Text)<bodyTMP>5__10).text, <usableWidth>5__11, 0f);
					<newHeight>5__14 = Mathf.Max(90f, <titlePref>5__12.y + <bodyPref>5__13.y + 28f);
					<rt>5__2.sizeDelta = new Vector2(<rt>5__2.sizeDelta.x, <newHeight>5__14);
					<t>5__15 = 0f;
					<start>5__16 = new Vector2(0f, -150f);
					<mid>5__17 = new Vector2(0f, 0f);
					<end>5__18 = new Vector2(0f, -150f);
					<rt>5__2.anchoredPosition = <start>5__16;
					<cg>5__19 = <go>5__1.AddComponent<CanvasGroup>();
					<cg>5__19.alpha = 0f;
					if (<>4__this.EnableSound && (Object)(object)<>4__this._clip != (Object)null)
					{
						<a>5__22 = <>4__this._audio;
						<a>5__22.clip = <>4__this._clip;
						<a>5__22.volume = Mathf.Clamp01(<>4__this.Volume);
						<a>5__22.Play();
						<a>5__22 = null;
					}
					<inDur>5__20 = 0.25f;
					goto IL_05e9;
				case 1:
					<>1__state = -1;
					goto IL_05e9;
				case 2:
					<>1__state = -1;
					<t>5__15 = 0f;
					<outDur>5__21 = 0.25f;
					break;
				case 3:
					{
						<>1__state = -1;
						break;
					}
					IL_05e9:
					if (<t>5__15 < <inDur>5__20)
					{
						<t>5__15 += Time.unscaledDeltaTime;
						<p>5__23 = <t>5__15 / <inDur>5__20;
						<e>5__24 = 1f - (1f - <p>5__23) * (1f - <p>5__23);
						<cg>5__19.alpha = <p>5__23;
						<rt>5__2.anchoredPosition = Vector2.Lerp(<start>5__16, <mid>5__17, <e>5__24);
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					<cg>5__19.alpha = 1f;
					<rt>5__2.anchoredPosition = <mid>5__17;
					<>2__current = (object)new WaitForSecondsRealtime(Mathf.Max(1f, <>4__this.Duration));
					<>1__state = 2;
					return true;
				}
				if (<t>5__15 < <outDur>5__21)
				{
					<t>5__15 += Time.unscaledDeltaTime;
					<p>5__25 = <t>5__15 / <outDur>5__21;
					<e>5__26 = <p>5__25 * <p>5__25;
					<cg>5__19.alpha = 1f - <p>5__25;
					<rt>5__2.anchoredPosition = Vector2.Lerp(<mid>5__17, <end>5__18, <e>5__26);
					<>2__current = null;
					<>1__state = 3;
					return true;
				}
				Object.Destroy((Object)(object)<go>5__1);
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		public float Duration = 3f;

		public float UiScale = 1f;

		public bool EnableSound = true;

		public string SoundFilePath;

		public float Volume = 0.7f;

		private Canvas _canvas;

		private RectTransform _root;

		private AudioSource _audio;

		private AudioClip _clip;

		private readonly Queue<ToastMessage> _queue = new Queue<ToastMessage>();

		private bool _busy;

		public void RefreshScale()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)_root))
			{
				((Transform)_root).localScale = Vector3.one * UiScale;
			}
		}

		private void Ensure()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)_canvas))
			{
				EmpressAchievementsPlugin.Log.LogInfo((object)"[ACH] Creating Toast Canvas...");
				_canvas = new GameObject("Empress_AchievementToastCanvas").AddComponent<Canvas>();
				Object.DontDestroyOnLoad((Object)(object)_canvas);
				_canvas.renderMode = (RenderMode)0;
				_canvas.sortingOrder = 32760;
				CanvasScaler val = ((Component)_canvas).gameObject.AddComponent<CanvasScaler>();
				val.uiScaleMode = (ScaleMode)1;
				val.referenceResolution = new Vector2(1920f, 1080f);
				val.screenMatchMode = (ScreenMatchMode)0;
				val.matchWidthOrHeight = 0.5f;
				((Component)_canvas).gameObject.AddComponent<GraphicRaycaster>();
				_root = new GameObject("ToastRoot").AddComponent<RectTransform>();
				((Transform)_root).SetParent(((Component)_canvas).transform, false);
				_root.anchorMin = new Vector2(0.5f, 0f);
				_root.anchorMax = new Vector2(0.5f, 0f);
				_root.pivot = new Vector2(0.5f, 0f);
				_root.anchoredPosition = new Vector2(0f, 80f);
				((Transform)_root).localScale = Vector3.one * UiScale;
				_audio = ((Component)_canvas).gameObject.AddComponent<AudioSource>();
				_audio.playOnAwake = false;
				_audio.spatialBlend = 0f;
				EmpressAchievementsPlugin.Log.LogInfo((object)"[ACH] Toast Canvas ready");
			}
		}

		[IteratorStateMachine(typeof(<LoadSoundCoroutine>d__13))]
		public IEnumerator LoadSoundCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadSoundCoroutine>d__13(0)
			{
				<>4__this = this
			};
		}

		private static AudioType GetAudioType(string path)
		{
			//IL_0025: 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_0057: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			return (AudioType)(Path.GetExtension(path)?.ToLowerInvariant() switch
			{
				".wav" => 20, 
				".ogg" => 14, 
				".mp3" => 13, 
				_ => 20, 
			});
		}

		public void Pop(string title, string body)
		{
			EmpressAchievementsPlugin.Log.LogInfo((object)("[ACH] Toast: " + title));
			Ensure();
			_queue.Enqueue(new ToastMessage(title, body));
			if (!_busy)
			{
				((MonoBehaviour)this).StartCoroutine(Run());
			}
		}

		[IteratorStateMachine(typeof(<Run>d__16))]
		private IEnumerator Run()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Run>d__16(0)
			{
				<>4__this = this
			};
		}

		[IteratorStateMachine(typeof(<ShowToast>d__17))]
		private IEnumerator ShowToast(string title, string body)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ShowToast>d__17(0)
			{
				<>4__this = this,
				title = title,
				body = body
			};
		}
	}
	public class AchievementsUi : MonoBehaviour
	{
		public float UiScale = 1f;

		private Canvas _canvas;

		private RectTransform _root;

		private GameObject _panel;

		private RectTransform _listRoot;

		private ScrollRect _scroll;

		private RectTransform _scrollRT;

		private TextMeshProUGUI _statsLabel;

		private RectTransform _statsRT;

		private RectTransform _headerRT;

		private bool _open;

		private float _nextStatsTick;

		public void RefreshScale()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)_root))
			{
				((Transform)_root).localScale = Vector3.one * UiScale;
			}
			if ((Object)(object)_panel != (Object)null && _panel.activeSelf)
			{
				RefreshList();
				RecomputeTopLayout();
				Canvas.ForceUpdateCanvases();
			}
		}

		private void Ensure()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)_canvas))
			{
				EmpressAchievementsPlugin.Log.LogInfo((object)"[ACH] Building Achievements Panel...]");
				_canvas = new GameObject("Empress_AchievementPanelCanvas").AddComponent<Canvas>();
				Object.DontDestroyOnLoad((Object)(object)_canvas);
				_canvas.renderMode = (RenderMode)0;
				_canvas.sortingOrder = 32700;
				CanvasScaler val = ((Component)_canvas).gameObject.AddComponent<CanvasScaler>();
				val.uiScaleMode = (ScaleMode)1;
				val.referenceResolution = new Vector2(1920f, 1080f);
				val.screenMatchMode = (ScreenMatchMode)0;
				val.matchWidthOrHeight = 0.5f;
				((Component)_canvas).gameObject.AddComponent<GraphicRaycaster>();
				_root = new GameObject("PanelRoot").AddComponent<RectTransform>();
				((Transform)_root).SetParent(((Component)_canvas).transform, false);
				_root.anchorMin = new Vector2(0.5f, 0.5f);
				_root.anchorMax = new Vector2(0.5f, 0.5f);
				_root.pivot = new Vector2(0.5f, 0.5f);
				_root.sizeDelta = new Vector2(1000f, 700f);
				((Transform)_root).localScale = Vector3.one * UiScale;
				_panel = BuildPanel(_root);
				_panel.SetActive(false);
			}
		}

		public void Toggle()
		{
			Ensure();
			_open = !_open;
			_panel.SetActive(_open);
			if (_open)
			{
				RefreshList();
				UpdateStatsLabel();
				RecomputeTopLayout();
				_nextStatsTick = Time.unscaledTime + 0.5f;
				Canvas.ForceUpdateCanvases();
			}
		}

		public void RefreshAllIfOpen()
		{
			if ((Object)(object)_panel != (Object)null && _panel.activeSelf)
			{
				UpdateStatsLabel();
				RecomputeTopLayout();
				RefreshList();
			}
		}

		public void RefreshStatsIfOpen()
		{
			if ((Object)(object)_panel != (Object)null && _panel.activeSelf)
			{
				UpdateStatsLabel();
				RecomputeTopLayout();
			}
		}

		public void RefreshList()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			Ensure();
			if ((Object)(object)_panel == (Object)null)
			{
				return;
			}
			foreach (Transform item in (Transform)_listRoot)
			{
				Transform val = item;
				Object.Destroy((Object)(object)((Component)val).gameObject);
			}
			foreach (AchievementDef item2 in AchievementBook.AllOrdered())
			{
				bool unlocked = EmpressAchievementsPlugin.Store.IsUnlocked(item2.Id);
				BuildEntry(_listRoot, item2, unlocked);
			}
			LayoutRebuilder.ForceRebuildLayoutImmediate(_listRoot);
		}

		private void Update()
		{
			if (!((Object)(object)_panel == (Object)null) && _panel.activeSelf && Time.unscaledTime >= _nextStatsTick)
			{
				UpdateStatsLabel();
				RecomputeTopLayout();
				_nextStatsTick = Time.unscaledTime + 0.5f;
			}
		}

		private void UpdateStatsLabel()
		{
			if (!((Object)(object)_statsLabel == (Object)null))
			{
				int stat = EmpressAchievementsPlugin.GetStat("extractions");
				int stat2 = EmpressAchievementsPlugin.GetStat("purchases");
				int stat3 = EmpressAchievementsPlugin.GetStat("deaths");
				int stat4 = EmpressAchievementsPlugin.GetStat("revives");
				long counter = EmpressAchievementsPlugin.Store.GetCounter("life_haul");
				long counter2 = EmpressAchievementsPlugin.Store.GetCounter("kills_total");
				string text = "$" + EmpressAchievementsPlugin.FormatK(counter);
				((TMP_Text)_statsLabel).text = $"Extractions: {stat}  |  Purchases: {stat2}  |  Deaths: {stat3}  |  Revives: {stat4}  |  Lifetime Haul: {text}  |  Kills: {counter2}";
			}
		}

		private GameObject BuildPanel(RectTransform parent)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Expected O, but got Unknown
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ba: Expected O, but got Unknown
			//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0406: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			//IL_0432: Unknown result type (might be due to invalid IL or missing references)
			//IL_0443: Unknown result type (might be due to invalid IL or missing references)
			//IL_0454: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ad: Expected O, but got Unknown
			//IL_04e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f0: Expected O, but got Unknown
			//IL_050f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0526: Unknown result type (might be due to invalid IL or missing references)
			//IL_053d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0554: Unknown result type (might be due to invalid IL or missing references)
			//IL_056b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0595: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c1: Expected O, but got Unknown
			//IL_05c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ce: Expected O, but got Unknown
			//IL_05e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0603: Unknown result type (might be due to invalid IL or missing references)
			//IL_0640: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Panel");
			RectTransform val2 = val.AddComponent<RectTransform>();
			((Transform)val2).SetParent((Transform)(object)parent, false);
			val2.sizeDelta = parent.sizeDelta;
			Image val3 = val.AddComponent<Image>();
			((Graphic)val3).color = new Color(0f, 0f, 0f, 0.85f);
			((Graphic)val3).raycastTarget = true;
			GameObject val4 = new GameObject("Header");
			_headerRT = val4.AddComponent<RectTransform>();
			((Transform)_headerRT).SetParent((Transform)(object)val2, false);
			_headerRT.anchorMin = new Vector2(0f, 1f);
			_headerRT.anchorMax = new Vector2(1f, 1f);
			_headerRT.pivot = new Vector2(0.5f, 1f);
			_headerRT.sizeDelta = new Vector2(0f, 60f);
			TextMeshProUGUI val5 = val4.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val5).text = "EMPRESS Achievements";
			((TMP_Text)val5).fontSize = 36f;
			((Graphic)val5).color = new Color(1f, 0.92f, 0.6f);
			((TMP_Text)val5).alignment = (TextAlignmentOptions)4098;
			((TMP_Text)val5).fontStyle = (FontStyles)1;
			((Graphic)val5).raycastTarget = false;
			GameObject val6 = new GameObject("Stats");
			_statsRT = val6.AddComponent<RectTransform>();
			((Transform)_statsRT).SetParent((Transform)(object)val2, false);
			_statsRT.anchorMin = new Vector2(0f, 1f);
			_statsRT.anchorMax = new Vector2(1f, 1f);
			_statsRT.pivot = new Vector2(0.5f, 1f);
			_statsRT.anchoredPosition = new Vector2(0f, -60f);
			_statsRT.sizeDelta = new Vector2(-20f, 100f);
			_statsLabel = val6.AddComponent<TextMeshProUGUI>();
			((TMP_Text)_statsLabel).fontSize = 18f;
			((TMP_Text)_statsLabel).alignment = (TextAlignmentOptions)4098;
			((TMP_Text)_statsLabel).enableWordWrapping = true;
			((TMP_Text)_statsLabel).overflowMode = (TextOverflowModes)0;
			((Graphic)_statsLabel).color = new Color(0.85f, 0.85f, 0.85f);
			((Graphic)_statsLabel).raycastTarget = false;
			((TMP_Text)_statsLabel).margin = new Vector4(10f, 10f, 10f, 10f);
			UpdateStatsLabel();
			GameObject val7 = new GameObject("ScrollViewport");
			_scrollRT = val7.AddComponent<RectTransform>();
			((Transform)_scrollRT).SetParent((Transform)(object)val2, false);
			_scrollRT.anchorMin = new Vector2(0f, 0f);
			_scrollRT.anchorMax = new Vector2(1f, 1f);
			_scrollRT.offsetMin = new Vector2(20f, 20f);
			_scrollRT.offsetMax = new Vector2(-20f, -180f);
			Image val8 = val7.AddComponent<Image>();
			((Graphic)val8).color = new Color(0.1f, 0.1f, 0.1f, 0.25f);
			RectMask2D val9 = val7.AddComponent<RectMask2D>();
			val9.padding = Vector4.zero;
			_scroll = val7.AddComponent<ScrollRect>();
			_scroll.horizontal = false;
			_scroll.vertical = true;
			_scroll.movementType = (MovementType)2;
			_scroll.scrollSensitivity = 20f;
			GameObject val10 = new GameObject("Content");
			_listRoot = val10.AddComponent<RectTransform>();
			((Transform)_listRoot).SetParent(val7.transform, false);
			_listRoot.anchorMin = new Vector2(0f, 1f);
			_listRoot.anchorMax = new Vector2(1f, 1f);
			_listRoot.pivot = new Vector2(0.5f, 1f);
			_listRoot.offsetMin = Vector2.zero;
			_listRoot.offsetMax = Vector2.zero;
			_listRoot.anchoredPosition = Vector2.zero;
			VerticalLayoutGroup val11 = val10.AddComponent<VerticalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)val11).childForceExpandHeight = false;
			((HorizontalOrVerticalLayoutGroup)val11).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)val11).childForceExpandWidth = true;
			((HorizontalOrVerticalLayoutGroup)val11).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)val11).spacing = 8f;
			((LayoutGroup)val11).padding = new RectOffset(12, 12, 12, 12);
			ContentSizeFitter val12 = val10.AddComponent<ContentSizeFitter>();
			val12.verticalFit = (FitMode)2;
			_scroll.content = _listRoot;
			_scroll.viewport = _scrollRT;
			GameObject val13 = new GameObject("CloseButton");
			RectTransform val14 = val13.AddComponent<RectTransform>();
			((Transform)val14).SetParent((Transform)(object)val2, false);
			val14.anchorMin = new Vector2(1f, 1f);
			val14.anchorMax = new Vector2(1f, 1f);
			val14.pivot = new Vector2(1f, 1f);
			val14.anchoredPosition = new Vector2(-15f, -15f);
			val14.sizeDelta = new Vector2(36f, 36f);
			Image val15 = val13.AddComponent<Image>();
			((Graphic)val15).color = new Color(0.8f, 0.2f, 0.2f, 0.8f);
			Button val16 = val13.AddComponent<Button>();
			((UnityEvent)val16.onClick).AddListener((UnityAction)delegate
			{
				Toggle();
			});
			GameObject val17 = new GameObject("X");
			RectTransform val18 = val17.AddComponent<RectTransform>();
			((Transform)val18).SetParent(val13.transform, false);
			val18.sizeDelta = Vector2.zero;
			val18.anchorMin = Vector2.zero;
			val18.anchorMax = Vector2.one;
			TextMeshProUGUI val19 = val17.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val19).text = "×";
			((TMP_Text)val19).fontSize = 22f;
			((TMP_Text)val19).alignment = (TextAlignmentOptions)4098;
			((Graphic)val19).color = Color.white;
			((TMP_Text)val19).fontStyle = (FontStyles)1;
			((Graphic)val19).raycastTarget = false;
			return val;
		}

		private float GetContentWidth()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			float num;
			Rect rect;
			if (!((Object)(object)_scrollRT != (Object)null))
			{
				if (!((Object)(object)_root != (Object)null))
				{
					num = 1000f;
				}
				else
				{
					rect = _root.rect;
					num = ((Rect)(ref rect)).width - 40f;
				}
			}
			else
			{
				rect = _scrollRT.rect;
				num = ((Rect)(ref rect)).width;
			}
			float num2 = num;
			return Mathf.Max(100f, num2 - 24f);
		}

		private void RecomputeTopLayout()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_statsLabel == (Object)null) && !((Object)(object)_statsRT == (Object)null) && !((Object)(object)_headerRT == (Object)null) && !((Object)(object)_scrollRT == (Object)null))
			{
				float num = GetContentWidth() + 20f;
				Vector2 preferredValues = ((TMP_Text)_statsLabel).GetPreferredValues(((TMP_Text)_statsLabel).text, num, 0f);
				float num2 = Mathf.Clamp(preferredValues.y + 20f, 60f, 180f);
				_statsRT.sizeDelta = new Vector2(-20f, num2);
				_scrollRT.offsetMax = new Vector2(-20f, 0f - (_headerRT.sizeDelta.y + num2 + 20f));
			}
		}

		private void BuildEntry(RectTransform parent, AchievementDef def, bool unlocked)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Expected O, but got Unknown
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02af: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(def.Id);
			RectTransform val2 = val.AddComponent<RectTransform>();
			((Transform)val2).SetParent((Transform)(object)parent, false);
			LayoutElement val3 = val.AddComponent<LayoutElement>();
			Image val4 = val.AddComponent<Image>();
			((Graphic)val4).color = (unlocked ? new Color(0.1f, 0.3f, 0.1f, 0.8f) : new Color(0.2f, 0.2f, 0.2f, 0.6f));
			((Graphic)val4).raycastTarget = false;
			GameObject val5 = new GameObject("Title");
			RectTransform val6 = val5.AddComponent<RectTransform>();
			((Transform)val6).SetParent((Transform)(object)val2, false);
			val6.anchorMin = new Vector2(0f, 0.5f);
			val6.anchorMax = new Vector2(1f, 1f);
			val6.offsetMin = new Vector2(15f, -8f);
			val6.offsetMax = new Vector2(-15f, -8f);
			TextMeshProUGUI val7 = val5.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val7).text = (unlocked ? def.Title : (def.Title + "  [LOCKED]"));
			((TMP_Text)val7).fontSize = 20f;
			((Graphic)val7).color = (unlocked ? new Color(0.9f, 1f, 0.9f) : new Color(0.75f, 0.75f, 0.75f));
			((TMP_Text)val7).alignment = (TextAlignmentOptions)4097;
			((TMP_Text)val7).fontStyle = (FontStyles)(unlocked ? 1 : 0);
			((TMP_Text)val7).enableWordWrapping = true;
			((TMP_Text)val7).overflowMode = (TextOverflowModes)1;
			((Graphic)val7).raycastTarget = false;
			GameObject val8 = new GameObject("Description");
			RectTransform val9 = val8.AddComponent<RectTransform>();
			((Transform)val9).SetParent((Transform)(object)val2, false);
			val9.anchorMin = new Vector2(0f, 0f);
			val9.anchorMax = new Vector2(1f, 0.5f);
			val9.offsetMin = new Vector2(15f, 8f);
			val9.offsetMax = new Vector2(-15f, 8f);
			TextMeshProUGUI val10 = val8.AddComponent<TextMeshProUGUI>();
			((TMP_Text)val10).text = (unlocked ? def.Description : "???");
			((TMP_Text)val10).fontSize = 15f;
			((Graphic)val10).color = (unlocked ? new Color(0.85f, 0.85f, 0.85f) : new Color(0.6f, 0.6f, 0.6f));
			((TMP_Text)val10).alignment = (TextAlignmentOptions)4097;
			((TMP_Text)val10).enableWordWrapping = true;
			((TMP_Text)val10).overflowMode = (TextOverflowModes)1;
			((Graphic)val10).raycastTarget = false;
			float contentWidth = GetContentWidth();
			Vector2 preferredValues = ((TMP_Text)val7).GetPreferredValues(((TMP_Text)val7).text, contentWidth, 0f);
			Vector2 preferredValues2 = ((TMP_Text)val10).GetPreferredValues(((TMP_Text)val10).text, contentWidth, 0f);
			float preferredHeight = (val3.minHeight = Mathf.Max(70f, preferredValues.y + preferredValues2.y + 32f));
			val3.preferredHeight = preferredHeight;
		}
	}
	[HarmonyPatch(typeof(RoundDirector), "StartRoundRPC")]
	public static class Patch_RoundStart
	{
		private static void Postfix()
		{
			int stat = EmpressAchievementsPlugin.GetStat("run_deaths");
			if (stat != 0)
			{
				EmpressAchievementsPlugin.Store.AddToCounter("run_deaths", -stat);
			}
			EmpressAchievementsPlugin.TalliedExtractionThisRound = false;
			EmpressAchievementsPlugin.ProcessedKillHashes.Clear();
		}
	}
	[HarmonyPatch(typeof(RoundDirector), "ExtractionCompleted")]
	public static class Patch_ExtractionCompleted
	{
		private static void Postfix()
		{
			if (EmpressAchievementsPlugin.TalliedExtractionThisRound)
			{
				ManualLogSource log = EmpressAchievementsPlugin.Log;
				if (log != null)
				{
					log.LogDebug((object)"[ACH] ExtractionCompleted duplicate ignored.");
				}
				return;
			}
			EmpressAchievementsPlugin.TalliedExtractionThisRound = true;
			EmpressAchievementsPlugin.BumpStat("extractions");
			EmpressAchievementsPlugin.Unlock("first_extract");
			int stat = EmpressAchievementsPlugin.GetStat("extractions");
			if (stat >= 5)
			{
				EmpressAchievementsPlugin.Unlock("extract_5");
			}
			if (stat >= 20)
			{
				EmpressAchievementsPlugin.Unlock("extract_20");
			}
			if (stat >= 50)
			{
				EmpressAchievementsPlugin.Unlock("extract_50");
			}
			if (stat >= 100)
			{
				EmpressAchievementsPlugin.Unlock("extract_100");
			}
			if (stat >= 200)
			{
				EmpressAchievementsPlugin.Unlock("extract_200");
			}
			try
			{
				int num = SemiFunc.StatGetRunTotalHaul();
				EmpressAchievementsPlugin.Store.AddToCounter("life_haul", num);
				if (num >= 10000)
				{
					EmpressAchievementsPlugin.Unlock("run_haul_10000");
				}
				if (num >= 25000)
				{
					EmpressAchievementsPlugin.Unlock("run_haul_25000");
				}
				if (num >= 50000)
				{
					EmpressAchievementsPlugin.Unlock("run_haul_50000");
				}
			}
			catch
			{
			}
			long counter = EmpressAchievementsPlugin.Store.GetCounter("life_haul");
			if (counter >= 50000)
			{
				EmpressAchievementsPlugin.Unlock("life_haul_50k");
			}
			if (counter >= 100000)
			{
				EmpressAchievementsPlugin.Unlock("life_haul_100k");
			}
			if (counter >= 250000)
			{
				EmpressAchievementsPlugin.Unlock("life_haul_250k");
			}
			if (counter >= 500000)
			{
				EmpressAchievementsPlugin.Unlock("life_haul_500k");
			}
			if (counter >= 1000000)
			{
				EmpressAchievementsPlugin.Unlock("life_haul_1m");
			}
			if (counter >= 2000000)
			{
				EmpressAchievementsPlugin.Unlock("life_haul_2m");
			}
			if (counter >= 5000000)
			{
				EmpressAchievementsPlugin.Unlock("life_haul_5m");
			}
			if (counter >= 10000000)
			{
				EmpressAchievementsPlugin.Unlock("life_haul_10m");
			}
			if (counter >= 20000000)
			{
				EmpressAchievementsPlugin.Unlock("life_haul_20m");
			}
			if (counter >= 50000000)
			{
				EmpressAchievementsPlugin.Unlock("life_haul_50m");
			}
			if (EmpressAchievementsPlugin.GetStat("run_deaths") == 0)
			{
				EmpressAchievementsPlugin.Unlock("nodeath_run");
			}
			EmpressAchievementsPlugin.Store.AddToCounter("run_deaths", -EmpressAchievementsPlugin.GetStat("run_deaths"));
		}
	}
	[HarmonyPatch(typeof(PunManager), "SetRunStatSet")]
	public static class Patch_RunStatSet
	{
		private static void Postfix(string statName, int value)
		{
			if (string.Equals(statName, "currency", StringComparison.OrdinalIgnoreCase))
			{
				if (value >= 10000)
				{
					EmpressAchievementsPlugin.Unlock("run_money_10000");
				}
				if (value >= 25000)
				{
					EmpressAchievementsPlugin.Unlock("run_money_25000");
				}
				if (value >= 50000)
				{
					EmpressAchievementsPlugin.Unlock("run_money_50000");
				}
				if (value >= 100000)
				{
					EmpressAchievementsPlugin.Unlock("run_money_100000");
				}
			}
			else if (string.Equals(statName, "totalHaul", StringComparison.OrdinalIgnoreCase))
			{
				if (value >= 10000)
				{
					EmpressAchievementsPlugin.Unlock("run_haul_10000");
				}
				if (value >= 25000)
				{
					EmpressAchievementsPlugin.Unlock("run_haul_25000");
				}
				if (value >= 50000)
				{
					EmpressAchievementsPlugin.Unlock("run_haul_50000");
				}
			}
		}
	}
	[HarmonyPatch(typeof(StatsManager), "ItemPurchase")]
	public static class Patch_ItemPurchase
	{
		private static void Postfix(string itemName)
		{
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime - EmpressAchievementsPlugin.LastPurchaseTime < 0.1f)
			{
				ManualLogSource log = EmpressAchievementsPlugin.Log;
				if (log != null)
				{
					log.LogDebug((object)"[ACH] Purchase duplicate ignored (debounce).");
				}
				return;
			}
			EmpressAchievementsPlugin.LastPurchaseTime = unscaledTime;
			EmpressAchievementsPlugin.BumpStat("purchases");
			int stat = EmpressAchievementsPlugin.GetStat("purchases");
			if (stat >= 1)
			{
				EmpressAchievementsPlugin.Unlock("first_purchase");
			}
			if (stat >= 10)
			{
				EmpressAchievementsPlugin.Unlock("big_spender_10");
			}
			if (stat >= 25)
			{
				EmpressAchievementsPlugin.Unlock("big_spender_25");
			}
			if (stat >= 50)
			{
				EmpressAchievementsPlugin.Unlock("big_spender_50");
			}
			if (stat >= 100)
			{
				EmpressAchievementsPlugin.Unlock("big_spender_100");
			}
			ManualLogSource log2 = EmpressAchievementsPlugin.Log;
			if (log2 != null)
			{
				log2.LogDebug((object)$"[ACH] Purchase tracked: {itemName}, total: {stat}");
			}
		}
	}
	[HarmonyPatch(typeof(StatsManager), "DictionaryUpdateValue")]
	public static class Patch_DictionaryUpdates
	{
		private static void Postfix(string dictionaryName, string key, int value)
		{
			if (!string.Equals(dictionaryName, "itemsPurchased", StringComparison.OrdinalIgnoreCase) && !string.Equals(dictionaryName, "itemsPurchasedTotal", StringComparison.OrdinalIgnoreCase))
			{
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "PlayerDeathRPC")]
	public static class Patch_PlayerDeath
	{
		private static void Postfix(PlayerAvatar __instance)
		{
			PhotonView val = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent<PhotonView>() : null);
			if ((Object)(object)val == (Object)null || !val.IsMine)
			{
				ManualLogSource log = EmpressAchievementsPlugin.Log;
				if (log != null)
				{
					log.LogDebug((object)"[ACH] Ignored death for non-local avatar.");
				}
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime - EmpressAchievementsPlugin.LastLocalDeathTime < 0.35f)
			{
				ManualLogSource log2 = EmpressAchievementsPlugin.Log;
				if (log2 != null)
				{
					log2.LogDebug((object)"[ACH] Death duplicate ignored (debounce).");
				}
				return;
			}
			EmpressAchievementsPlugin.LastLocalDeathTime = unscaledTime;
			EmpressAchievementsPlugin.BumpStat("deaths");
			EmpressAchievementsPlugin.BumpStat("run_deaths");
			int stat = EmpressAchievementsPlugin.GetStat("deaths");
			EmpressAchievementsPlugin.Unlock("first_death");
			if (stat >= 5)
			{
				EmpressAchievementsPlugin.Unlock("death_5");
			}
			if (stat >= 10)
			{
				EmpressAchievementsPlugin.Unlock("death_10");
			}
			if (stat >= 20)
			{
				EmpressAchievementsPlugin.Unlock("death_20");
			}
			if (stat >= 30)
			{
				EmpressAchievementsPlugin.Unlock("death_30");
			}
			if (stat >= 40)
			{
				EmpressAchievementsPlugin.Unlock("death_40");
			}
			if (stat >= 50)
			{
				EmpressAchievementsPlugin.Unlock("death_50");
			}
			if (stat >= 100)
			{
				EmpressAchievementsPlugin.Unlock("death_100");
			}
			if (stat >= 200)
			{
				EmpressAchievementsPlugin.Unlock("death_200");
			}
			if (stat >= 500)
			{
				EmpressAchievementsPlugin.Unlock("death_500");
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "ReviveRPC")]
	public static class Patch_PlayerRevive
	{
		private static void Postfix()
		{
			EmpressAchievementsPlugin.BumpStat("revives");
			EmpressAchievementsPlugin.Unlock("revived");
			int stat = EmpressAchievementsPlugin.GetStat("revives");
			if (stat >= 10)
			{
				EmpressAchievementsPlugin.Unlock("revived_10");
			}
			if (stat >= 50)
			{
				EmpressAchievementsPlugin.Unlock("revived_50");
			}
		}
	}
	[HarmonyPatch(typeof(ValuableObject), "DiscoverRPC")]
	public static class Patch_Discover
	{
		private static void Postfix()
		{
			EmpressAchievementsPlugin.Unlock("first_discover");
		}
	}
	[HarmonyPatch(typeof(EnemyHealth), "DeathRPC")]
	public static class Patch_EnemyDeath
	{
		private static void Postfix(EnemyHealth __instance, PhotonMessageInfo _info)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if (!SemiFunc.MasterOnlyRPC(_info))
			{
				return;
			}
			try
			{
				int item = ((Object)__instance).GetInstanceID() ^ (int)(((PhotonMessageInfo)(ref _info)).SentServerTime * 1000.0);
				if (EmpressAchievementsPlugin.ProcessedKillHashes.Contains(item))
				{
					ManualLogSource log = EmpressAchievementsPlugin.Log;
					if (log != null)
					{
						log.LogDebug((object)"[ACH] Kill duplicate ignored (hash).");
					}
					return;
				}
				EmpressAchievementsPlugin.ProcessedKillHashes.Add(item);
				Enemy component = ((Component)__instance).GetComponent<Enemy>();
				string text = (((Object)(object)component != (Object)null) ? ((object)(EnemyType)(ref component.Type)).ToString() : "Unknown");
				EmpressAchievementsPlugin.Store.AddToCounter("kills_total", 1L);
				EmpressAchievementsPlugin.Store.AddToCounter("kills_type_" + text, 1L);
				long counter = EmpressAchievementsPlugin.Store.GetCounter("kills_total");
				if (counter >= 10)
				{
					EmpressAchievementsPlugin.Unlock("kills_10");
				}
				if (counter >= 50)
				{
					EmpressAchievementsPlugin.Unlock("kills_50");
				}
				if (counter >= 100)
				{
					EmpressAchievementsPlugin.Unlock("kills_100");
				}
				if (counter >= 250)
				{
					EmpressAchievementsPlugin.Unlock("kills_250");
				}
				if (counter >= 500)
				{
					EmpressAchievementsPlugin.Unlock("kills_500");
				}
				if (counter >= 1000)
				{
					EmpressAchievementsPlugin.Unlock("kills_1000");
				}
				if (counter >= 2000)
				{
					EmpressAchievementsPlugin.Unlock("kills_2000");
				}
				if (counter >= 5000)
				{
					EmpressAchievementsPlugin.Unlock("kills_5000");
				}
				if (!string.IsNullOrEmpty(text))
				{
					switch (text)
					{
					case "VeryLight":
						EmpressAchievementsPlugin.Unlock("kill_type_VeryLight");
						break;
					case "Light":
						EmpressAchievementsPlugin.Unlock("kill_type_Light");
						break;
					case "Medium":
						EmpressAchievementsPlugin.Unlock("kill_type_Medium");
						break;
					case "Heavy":
						EmpressAchievementsPlugin.Unlock("kill_type_Heavy");
						break;
					case "VeryHeavy":
						EmpressAchievementsPlugin.Unlock("kill_type_VeryHeavy");
						break;
					}
					long counter2 = EmpressAchievementsPlugin.Store.GetCounter("kills_type_" + text);
					if (text == "VeryLight" && counter2 >= 25)
					{
						EmpressAchievementsPlugin.Unlock("kill_type_VeryLight_25");
					}
					else if (text == "Light" && counter2 >= 25)
					{
						EmpressAchievementsPlugin.Unlock("kill_type_Light_25");
					}
					else if (text == "Medium" && counter2 >= 25)
					{
						EmpressAchievementsPlugin.Unlock("kill_type_Medium_25");
					}
					else if (text == "Heavy" && counter2 >= 25)
					{
						EmpressAchievementsPlugin.Unlock("kill_type_Heavy_25");
					}
					else if (text == "VeryHeavy" && counter2 >= 25)
					{
						EmpressAchievementsPlugin.Unlock("kill_type_VeryHeavy_25");
					}
				}
				ManualLogSource log2 = EmpressAchievementsPlugin.Log;
				if (log2 != null)
				{
					log2.LogDebug((object)$"[ACH] Kill tracked: {text}, total: {counter}");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log3 = EmpressAchievementsPlugin.Log;
				if (log3 != null)
				{
					log3.LogWarning((object)("[ACH] EnemyDeath tally error: " + ex));
				}
			}
		}
	}
}