Decompiled source of Divine Delivery v2.2.2

plugins/Divine Delivery/EndlessDelivery.Api.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using EndlessDelivery.Api.Exceptions;
using EndlessDelivery.Api.Requests;
using EndlessDelivery.Common;
using EndlessDelivery.Common.Communication.Scores;
using EndlessDelivery.Common.ContentFile;
using EndlessDelivery.Common.Inventory.Items;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;

[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.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("EndlessDelivery.Api")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+b5dc0c560e2a25aa15f1eef619719550a062d078")]
[assembly: AssemblyProduct("EndlessDelivery.Api")]
[assembly: AssemblyTitle("EndlessDelivery.Api")]
[assembly: AssemblyVersion("1.0.0.0")]
[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;
		}
	}
}
public class BadRequestException : Exception
{
	public BadRequestException(string reason)
		: base("Server rejected request as " + reason)
	{
	}
}
namespace EndlessDelivery.Api
{
	public class ApiContext
	{
		private const string ProdUrl = "https://delivery.wafflethings.dev/api/";

		public readonly Uri BaseUri;

		public readonly HttpClient Client;

		public string? Token;

		private readonly Func<string> _getTicket;

		public ApiContext(HttpClient client, Func<string> getTicket, Uri? baseUri = null)
		{
			Client = client;
			_getTicket = getTicket;
			if (baseUri != null && !baseUri.AbsoluteUri.EndsWith("/"))
			{
				baseUri = new Uri(baseUri.OriginalString + "/");
			}
			BaseUri = ((baseUri == null) ? new Uri("https://delivery.wafflethings.dev/api/") : baseUri);
		}

		public async Task Login()
		{
			Token = await this.GetToken(_getTicket());
		}

		public async Task AddAuth(HttpRequestMessage request)
		{
			try
			{
				if (Token == null)
				{
					throw new PermissionException("You must be logged in.");
				}
				request.Headers.Add("DeliveryToken", Token);
			}
			catch (InternalServerException ex)
			{
				await Task.FromException(ex);
			}
		}
	}
}
namespace EndlessDelivery.Api.Requests
{
	public static class Api
	{
		private const string PingEndpoint = "ping";

		private const string UpdateRequiredEndpoint = "update_required";

		public static async Task<bool> ServerOnline(this ApiContext context)
		{
			return (await context.Client.GetAsync(context.BaseUri?.ToString() + "ping")).IsSuccessStatusCode;
		}

		public static async Task<bool> UpdateRequired(this ApiContext context)
		{
			string content = await (await context.Client.GetAsync(context.BaseUri?.ToString() + $"update_required")).Content.ReadAsStringAsync();
			if (!bool.TryParse(content, out var result))
			{
				throw new BadResponseException(content);
			}
			return result;
		}
	}
	public static class Authentication
	{
		private const string LoginEndpoint = "auth/steam/login";

		public static async Task<string> GetToken(this ApiContext context, string ticket)
		{
			HttpResponseMessage response = await context.Client.PostAsync(context.BaseUri?.ToString() + "auth/steam/login", new StringContent(ticket));
			if (!response.IsSuccessStatusCode)
			{
				throw new InternalServerException();
			}
			return await response.Content.ReadAsStringAsync();
		}
	}
	public static class Content
	{
		private const string CmsRoot = "cms/";

		private const string UpdateRequiredEndpoint = "update_required?hash={0}";

		private const string DownloadCmsEndpoint = "content";

		public static async Task<bool> ContentUpdateRequired(this ApiContext context, string hash)
		{
			HttpResponseMessage response = await context.Client.GetAsync(context.BaseUri?.ToString() + "cms/" + $"update_required?hash={hash}");
			if (response.IsSuccessStatusCode)
			{
				return false;
			}
			if (response.StatusCode != HttpStatusCode.UpgradeRequired)
			{
				throw new BadResponseException("CMS download error " + response.StatusCode);
			}
			return true;
		}

		public static async Task<Cms> DownloadCms(this ApiContext context)
		{
			string content = await (await context.Client.GetAsync(context.BaseUri?.ToString() + "cms/content")).Content.ReadAsStringAsync();
			return JsonConvert.DeserializeObject<Cms>(content) ?? throw new BadResponseException(content);
		}
	}
	public static class Items
	{
		private const string ItemsRoot = "users/items/";

		private const string BuyItemEndpoint = "buy_item";

		private const string ActiveShopEndpoint = "active_shop";

		private const string GetLoadoutEndpoint = "get_loadout?steamId={0}";

		private const string SetLoadoutEndpoint = "set_loadout";

		private const string GetInventoryEndpoint = "get_inventory?steamId={0}";

		private const string ClaimDailyRewardEndpoint = "claim_daily_reward";

		private const string GetClaimedRewardsEndpoint = "get_claimed_rewards";

		public static async Task BuyItem(this ApiContext context, string itemId)
		{
			HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, context.BaseUri?.ToString() + "users/items/buy_item");
			await context.AddAuth(request);
			request.Content = new StringContent(itemId);
			HttpResponseMessage response = await context.Client.SendAsync(request);
			if (response.StatusCode == HttpStatusCode.BadRequest)
			{
				throw new BadRequestException(await response.Content.ReadAsStringAsync());
			}
		}

		public static async Task<ShopRotation> GetActiveShop(this ApiContext context)
		{
			string content = await (await context.Client.GetAsync(context.BaseUri?.ToString() + "users/items/active_shop")).Content.ReadAsStringAsync();
			return JsonConvert.DeserializeObject<ShopRotation>(content) ?? throw new BadResponseException(content);
		}

		public static async Task<CosmeticLoadout> GetLoadout(this ApiContext context, ulong steamId)
		{
			string content = await (await context.Client.GetAsync(context.BaseUri?.ToString() + "users/items/" + $"get_loadout?steamId={steamId}")).Content.ReadAsStringAsync();
			CosmeticLoadout deserialized = JsonConvert.DeserializeObject<CosmeticLoadout>(content);
			return deserialized ?? throw new BadResponseException(content);
		}

		public static async Task SetLoadout(this ApiContext context, CosmeticLoadout loadout)
		{
			HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, context.BaseUri?.ToString() + "users/items/set_loadout");
			await context.AddAuth(request);
			request.Content = new StringContent(JsonConvert.SerializeObject((object)loadout));
			HttpResponseMessage response = await context.Client.SendAsync(request);
			if (response.StatusCode == HttpStatusCode.BadRequest)
			{
				throw new BadRequestException(await response.Content.ReadAsStringAsync());
			}
		}

		public static async Task<List<string>> GetInventory(this ApiContext context, ulong steamId)
		{
			HttpResponseMessage response = await context.Client.GetAsync(context.BaseUri?.ToString() + "users/items/" + $"get_inventory?steamId={steamId}");
			if (response.StatusCode == HttpStatusCode.BadRequest)
			{
				throw new BadRequestException(await response.Content.ReadAsStringAsync());
			}
			if (response.StatusCode == HttpStatusCode.InternalServerError)
			{
				throw new InternalServerException();
			}
			string content = await response.Content.ReadAsStringAsync();
			List<string> deserialized = JsonConvert.DeserializeObject<List<string>>(content);
			if (deserialized == null)
			{
				throw new BadResponseException(content);
			}
			return deserialized;
		}

		public static async Task ClaimDailyReward(this ApiContext context)
		{
			HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, context.BaseUri?.ToString() + "users/items/claim_daily_reward");
			await context.AddAuth(request);
			HttpResponseMessage response = await context.Client.SendAsync(request);
			if (response.StatusCode == HttpStatusCode.BadRequest)
			{
				throw new BadRequestException(await response.Content.ReadAsStringAsync());
			}
		}

		public static async Task<List<string>> GetClaimedDailyRewards(this ApiContext context)
		{
			HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, context.BaseUri?.ToString() + "users/items/get_claimed_rewards");
			await context.AddAuth(request);
			HttpResponseMessage response = await context.Client.SendAsync(request);
			if (response.StatusCode == HttpStatusCode.BadRequest)
			{
				throw new BadRequestException(await response.Content.ReadAsStringAsync());
			}
			string content = await response.Content.ReadAsStringAsync();
			List<string> deserialized = JsonConvert.DeserializeObject<List<string>>(content);
			if (deserialized == null)
			{
				throw new BadResponseException(content);
			}
			return deserialized;
		}
	}
	public static class Scores
	{
		private const string ScoreRoot = "scores/";

		private const string GetRangeEndpoint = "get_range?start={0}&count={1}";

		private const string GetPositionEndpoint = "get_position?steamId={0}";

		private const string GetScoreEndpoint = "get_score?steamId={0}";

		private const string GetLengthEndpoint = "get_length";

		private const string SubmitScoreEndpoint = "submit_score";

		public static async Task<OnlineScore[]> GetScoreRange(this ApiContext context, int startIndex, int amount)
		{
			string content = await (await context.Client.GetAsync(context.BaseUri?.ToString() + "scores/" + $"get_range?start={startIndex}&count={amount}")).Content.ReadAsStringAsync();
			return JsonConvert.DeserializeObject<OnlineScore[]>(content) ?? throw new BadResponseException(content);
		}

		public static async Task<int> GetLeaderboardPosition(this ApiContext context, ulong userId)
		{
			string content = await (await context.Client.GetAsync(context.BaseUri?.ToString() + "scores/" + $"get_position?steamId={userId}")).Content.ReadAsStringAsync();
			if (!int.TryParse(content, out var pos))
			{
				throw new BadResponseException(content);
			}
			return pos;
		}

		public static async Task<OnlineScore> GetLeaderboardScore(this ApiContext context, ulong userId)
		{
			HttpResponseMessage response = await context.Client.GetAsync(context.BaseUri?.ToString() + "scores/" + $"get_score?steamId={userId}");
			if (response.StatusCode == HttpStatusCode.NotFound)
			{
				throw new NotFoundException(await response.Content.ReadAsStringAsync());
			}
			string content = await response.Content.ReadAsStringAsync();
			OnlineScore deserialized = JsonConvert.DeserializeObject<OnlineScore>(content);
			return deserialized ?? throw new BadResponseException(content);
		}

		public static async Task<int> GetLeaderboardLength(this ApiContext context)
		{
			string content = await (await context.Client.GetAsync(context.BaseUri?.ToString() + "scores/get_length")).Content.ReadAsStringAsync();
			if (!int.TryParse(content, out var length))
			{
				throw new BadResponseException(content);
			}
			return length;
		}

		public static async Task<OnlineScore> SubmitScore(this ApiContext context, SubmitScoreData scoreData)
		{
			HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, context.BaseUri?.ToString() + "scores/submit_score");
			await context.AddAuth(request);
			request.Content = new StringContent(JsonConvert.SerializeObject((object)scoreData));
			string content = await (await context.Client.SendAsync(request)).Content.ReadAsStringAsync();
			OnlineScore score = JsonConvert.DeserializeObject<OnlineScore>(content);
			return score ?? throw new BadResponseException(content);
		}
	}
	public static class Users
	{
		private const string UsersRoot = "users/";

		private const string GetCurrencyAmountEndpoint = "get_currency_amount";

		private const string GetAchievementsEndpoint = "get_achievements?steamId={0}";

		private const string GrantAchievementEndpoint = "grant_achievement";

		private const string GetUsernameEndpoint = "get_username?steamId={0}";

		private const string LifetimeStatsEndpoint = "lifetime_stats?steamId={0}";

		private const string GetBestScoreEndpoint = "get_best_score?steamId={0}";

		public static async Task<int> GetCurrencyAmount(this ApiContext context)
		{
			HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, context.BaseUri?.ToString() + "users/get_currency_amount");
			await context.AddAuth(request);
			HttpResponseMessage response = await context.Client.SendAsync(request);
			if (response.StatusCode == HttpStatusCode.InternalServerError)
			{
				throw new InternalServerException();
			}
			if (response.StatusCode == HttpStatusCode.BadRequest)
			{
				throw new BadRequestException(await response.Content.ReadAsStringAsync());
			}
			string content = await response.Content.ReadAsStringAsync();
			if (!int.TryParse(content, out var amount))
			{
				throw new BadResponseException(content);
			}
			return amount;
		}

		public static async Task<List<OwnedAchievement>> GetAchievements(this ApiContext context, ulong userId)
		{
			HttpResponseMessage response = await context.Client.GetAsync(context.BaseUri?.ToString() + "users/" + $"get_achievements?steamId={userId}");
			if (response.StatusCode == HttpStatusCode.NotFound)
			{
				throw new BadRequestException($"the user with ID {userId} was not found");
			}
			if (response.StatusCode == HttpStatusCode.InternalServerError)
			{
				throw new InternalServerException();
			}
			string content = await response.Content.ReadAsStringAsync();
			List<OwnedAchievement> list = JsonConvert.DeserializeObject<List<OwnedAchievement>>(content);
			return list ?? throw new BadResponseException(content);
		}

		public static async Task<string> GetUsername(this ApiContext context, ulong userId)
		{
			HttpResponseMessage response = await context.Client.GetAsync(context.BaseUri?.ToString() + "users/" + $"get_username?steamId={userId}");
			if (response.StatusCode == HttpStatusCode.NotFound)
			{
				throw new BadRequestException($"the user with ID {userId} was not found");
			}
			return await response.Content.ReadAsStringAsync();
		}

		public static async Task GrantAchievement(this ApiContext context, string achievementId)
		{
			HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, context.BaseUri?.ToString() + "users/grant_achievement");
			await context.AddAuth(request);
			request.Content = new StringContent(achievementId);
			HttpResponseMessage response = await context.Client.SendAsync(request);
			if (response.StatusCode == HttpStatusCode.InternalServerError)
			{
				throw new InternalServerException();
			}
			if (response.StatusCode == HttpStatusCode.BadRequest)
			{
				throw new BadRequestException(await response.Content.ReadAsStringAsync());
			}
		}

		public static async Task<Score> GetLifetimeStats(this ApiContext context, ulong userId)
		{
			HttpResponseMessage response = await context.Client.GetAsync(context.BaseUri?.ToString() + "users/" + $"lifetime_stats?steamId={userId}");
			if (response.StatusCode == HttpStatusCode.NotFound)
			{
				throw new BadRequestException($"the user with ID {userId} was not found");
			}
			if (response.StatusCode == HttpStatusCode.InternalServerError)
			{
				throw new InternalServerException();
			}
			string content = await response.Content.ReadAsStringAsync();
			Score deserialized = JsonConvert.DeserializeObject<Score>(content);
			return deserialized ?? throw new BadResponseException(content);
		}

		public static async Task<OnlineScore> GetBestScore(this ApiContext context, ulong userId)
		{
			HttpResponseMessage response = await context.Client.GetAsync(context.BaseUri?.ToString() + "users/" + $"get_best_score?steamId={userId}");
			if (response.StatusCode == HttpStatusCode.NotFound)
			{
				throw new BadRequestException($"the user with ID {userId} was not found");
			}
			if (response.StatusCode == HttpStatusCode.InternalServerError)
			{
				throw new InternalServerException();
			}
			string content = await response.Content.ReadAsStringAsync();
			OnlineScore deserialized = JsonConvert.DeserializeObject<OnlineScore>(content);
			return deserialized ?? throw new BadResponseException(content);
		}
	}
}
namespace EndlessDelivery.Api.Exceptions
{
	public class BadResponseException : Exception
	{
		public BadResponseException(string response)
			: base("Failed to parse response. Library may be out of date or server offline (\"" + response + "\").")
		{
		}
	}
	public class InternalServerException : Exception
	{
		public InternalServerException()
			: base("Internal server error.")
		{
		}
	}
	public class NotFoundException : Exception
	{
		public NotFoundException(string serverReason)
			: base("Not found - " + serverReason)
		{
		}
	}
	public class PermissionException : Exception
	{
		public PermissionException(string requirement = "")
			: base("The current user has insufficient permissions to perform this action. " + requirement)
		{
		}
	}
}

plugins/Divine Delivery/EndlessDelivery.Common.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using EndlessDelivery.Common.Communication.Scores;
using EndlessDelivery.Common.Inventory.Items;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;

[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.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("EndlessDelivery.Common")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+b5dc0c560e2a25aa15f1eef619719550a062d078")]
[assembly: AssemblyProduct("EndlessDelivery.Common")]
[assembly: AssemblyTitle("EndlessDelivery.Common")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 EndlessDelivery.Common
{
	public class Achievement
	{
		public string Name;

		public string Id;

		public string Description;

		public ClientWebPair Icon;

		public string[] ItemGrants;

		public bool HideDetails;

		public bool Serverside;

		public bool Disabled = false;
	}
	public static class DdUtils
	{
		public static string IntToDifficulty(int diff)
		{
			if (1 == 0)
			{
			}
			string result = diff switch
			{
				0 => "HARMLESS", 
				1 => "LENIENT", 
				2 => "STANDARD", 
				3 => "VIOLENT", 
				4 => "BRUTAL", 
				5 => "UKMD", 
				_ => throw new Exception("Invalid difficulty."), 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public static string ToWordString(this TimeSpan timeSpan)
		{
			string text = string.Format("{0} minute{1}", timeSpan.Minutes, (timeSpan.Minutes == 1) ? string.Empty : "s");
			if (timeSpan.Hours > 0)
			{
				text = string.Format("{0} hour{1}, ", timeSpan.Hours, (timeSpan.Hours == 1) ? string.Empty : "s") + text;
			}
			if (timeSpan.Days > 0)
			{
				text = string.Format("{0} day{1}, ", timeSpan.Days, (timeSpan.Days == 1) ? string.Empty : "s") + text;
			}
			return text;
		}
	}
	public class OwnedAchievement
	{
		public DateTime Achieved;

		public string Id;

		public OwnedAchievement(DateTime achieved, string id)
		{
			Achieved = achieved;
			Id = id;
		}

		public OwnedAchievement()
		{
		}
	}
	public class Score
	{
		public readonly int Rooms;

		public readonly int Kills;

		public readonly int Deliveries;

		public readonly float Time;

		public readonly int StartRoom;

		[JsonIgnore]
		public int MoneyGain => Deliveries / 4 * 10 + Kills / 5;

		private static bool IsLargerThanOtherScore(Score score, Score other)
		{
			if (score.Rooms != other.Rooms)
			{
				if (score.Rooms > other.Rooms)
				{
					return true;
				}
				return false;
			}
			if (score.Deliveries != other.Deliveries)
			{
				if (score.Deliveries > other.Deliveries)
				{
					return true;
				}
				return false;
			}
			if (score.Kills != other.Kills)
			{
				if (score.Kills > other.Kills)
				{
					return true;
				}
				return false;
			}
			if (score.Time != other.Time)
			{
				if (score.Time < other.Time)
				{
					return true;
				}
				return false;
			}
			return false;
		}

		public Score(int rooms, int kills, int deliveries, float time, int startRoom = 0)
		{
			Rooms = rooms;
			Kills = kills;
			Deliveries = deliveries;
			Time = time;
			StartRoom = startRoom;
		}

		public static Score operator +(Score a, Score b)
		{
			return new Score(a.Rooms + b.Rooms, a.Kills + b.Kills, a.Deliveries + b.Deliveries, a.Time + b.Time);
		}

		public static Score operator -(Score a, Score b)
		{
			return new Score(a.Rooms - b.Rooms, a.Kills - b.Kills, a.Deliveries - b.Deliveries, a.Time - b.Time);
		}

		public static bool operator >(Score a, Score b)
		{
			return IsLargerThanOtherScore(a, b);
		}

		public static bool operator <(Score a, Score b)
		{
			return IsLargerThanOtherScore(b, a);
		}

		public override string ToString()
		{
			return $"[Score {Rooms} {Kills} {Deliveries} {Time}]";
		}
	}
}
namespace EndlessDelivery.Common.Inventory.Items
{
	public class Banner : Item
	{
		public ClientWebPair Asset;

		public Banner(ClientWebPair asset, ItemDescriptor descriptor)
			: base(descriptor)
		{
			Asset = asset;
		}

		public Banner()
		{
		}
	}
	[Serializable]
	public class ClientWebPair
	{
		public string AssetUri;

		public string AddressablePath;
	}
	public class CosmeticLoadout
	{
		public static readonly List<string> DefaultItems = new List<string>(10) { "revolver_default", "altrevolver_default", "shotgun_default", "altshotgun_default", "nailgun_default", "altnailgun_default", "railcannon_default", "rocket_default", "banner_default", "present_default" };

		public string BannerId;

		public string PresentId;

		public List<string> RevolverIds = new List<string>();

		public List<string> AltRevolverIds = new List<string>();

		public List<string> ShotgunIds = new List<string>();

		public List<string> AltShotgunIds = new List<string>();

		public List<string> NailgunIds = new List<string>();

		public List<string> AltNailgunIds = new List<string>();

		public List<string> RailcannonIds = new List<string>();

		public List<string> RocketIds = new List<string>();

		public static CosmeticLoadout Default => new CosmeticLoadout
		{
			BannerId = "banner_default",
			PresentId = "present_default",
			RevolverIds = new List<string>(3) { "revolver_default", "revolver_default", "revolver_default" },
			AltRevolverIds = new List<string>(3) { "altrevolver_default", "altrevolver_default", "altrevolver_default" },
			ShotgunIds = new List<string>(3) { "shotgun_default", "shotgun_default", "shotgun_default" },
			AltShotgunIds = new List<string>(3) { "altshotgun_default", "altshotgun_default", "altshotgun_default" },
			NailgunIds = new List<string>(3) { "nailgun_default", "nailgun_default", "nailgun_default" },
			AltNailgunIds = new List<string>(3) { "altnailgun_default", "altnailgun_default", "altnailgun_default" },
			RailcannonIds = new List<string>(3) { "railcannon_default", "railcannon_default", "railcannon_default" },
			RocketIds = new List<string>(3) { "rocket_default", "rocket_default", "rocket_default" }
		};
	}
	public abstract class Item
	{
		public ItemDescriptor Descriptor;

		public Item(ItemDescriptor descriptor)
		{
			Descriptor = descriptor;
		}

		protected Item()
		{
		}
	}
	public class ItemDescriptor
	{
		public StoreItemType Type;

		public string Id;

		public string Name;

		public int ShopPrice;

		public ClientWebPair Icon;

		public ItemDescriptor(string id, string name, ClientWebPair icon, StoreItemType type, int shopPrice = 0)
		{
			Id = id;
			Name = name;
			Icon = icon;
			Type = type;
			ShopPrice = shopPrice;
		}

		public ItemDescriptor()
		{
		}
	}
	public enum StoreItemType
	{
		Banner,
		Revolver,
		Shotgun,
		Nailgun,
		Rail,
		Rocket,
		Present,
		AltRevolver,
		AltShotgun,
		AltNailgun
	}
	public class WeaponSkinItem : Item
	{
	}
	public enum GunType
	{
		Revolver,
		AltRevolver,
		Shotgun,
		AltShotgun,
		Nailgun,
		AltNailgun,
		Railcannon,
		RocketLauncher
	}
}
namespace EndlessDelivery.Common.ContentFile
{
	public class CalendarReward
	{
		public bool IsLastDay;

		public DateTime Date;

		public string Name;

		public string Description;

		public string Subtitle;

		public ClientWebPair Icon;

		public string Id;

		public bool HasItem;

		public string ItemId;

		public bool HasCurrency;

		public int CurrencyAmount;
	}
	public class Cms
	{
		public List<DatedRoomPool> RoomPools = new List<DatedRoomPool>();

		public Dictionary<string, CalendarReward> CalendarRewards = new Dictionary<string, CalendarReward>();

		public Dictionary<string, Achievement> Achievements = new Dictionary<string, Achievement>();

		public Dictionary<string, Banner> Banners = new Dictionary<string, Banner>();

		public Dictionary<string, WeaponSkinItem> Revolvers = new Dictionary<string, WeaponSkinItem>();

		public Dictionary<string, WeaponSkinItem> AltRevolvers = new Dictionary<string, WeaponSkinItem>();

		public Dictionary<string, WeaponSkinItem> Shotguns = new Dictionary<string, WeaponSkinItem>();

		public Dictionary<string, WeaponSkinItem> AltShotguns = new Dictionary<string, WeaponSkinItem>();

		public Dictionary<string, WeaponSkinItem> Nailguns = new Dictionary<string, WeaponSkinItem>();

		public Dictionary<string, WeaponSkinItem> AltNailguns = new Dictionary<string, WeaponSkinItem>();

		public Dictionary<string, WeaponSkinItem> Railcannons = new Dictionary<string, WeaponSkinItem>();

		public Dictionary<string, WeaponSkinItem> Rockets = new Dictionary<string, WeaponSkinItem>();

		public Dictionary<string, WeaponSkinItem> Presents = new Dictionary<string, WeaponSkinItem>();

		public List<ShopRotation> ShopRotations = new List<ShopRotation>();

		public Dictionary<string, string> Strings = new Dictionary<string, string>();

		public Dictionary<string, string> BannedMods = new Dictionary<string, string>();

		[JsonIgnore]
		public string Hash
		{
			get
			{
				using MD5 mD = MD5.Create();
				string s = JsonConvert.SerializeObject((object)this, (Formatting)0);
				byte[] bytes = Encoding.UTF8.GetBytes(s);
				byte[] array = mD.ComputeHash(bytes);
				return BitConverter.ToString(array).Replace("-", "").ToLowerInvariant();
			}
		}

		[JsonIgnore]
		public CalendarReward CurrentCalendarReward => CalendarRewards.FirstOrDefault((KeyValuePair<string, CalendarReward> x) => x.Value.Date == DateTime.UtcNow.Date).Value;

		[JsonIgnore]
		public ShopRotation ActiveShopRotation
		{
			get
			{
				foreach (ShopRotation shopRotation in ShopRotations)
				{
					if (shopRotation.Start > DateTime.UtcNow || shopRotation.Start + shopRotation.Length < DateTime.UtcNow)
					{
						continue;
					}
					return shopRotation;
				}
				return null;
			}
		}

		[JsonIgnore]
		public DatedRoomPool? CurrentRoomPool
		{
			get
			{
				DatedRoomPool datedRoomPool = null;
				foreach (DatedRoomPool roomPool in RoomPools)
				{
					if (datedRoomPool == null || (roomPool.After > datedRoomPool.After && roomPool.After <= DateTime.UtcNow))
					{
						datedRoomPool = roomPool;
					}
				}
				return datedRoomPool;
			}
		}

		public string GetString(string id)
		{
			return Strings.ContainsKey(id) ? Strings[id] : id;
		}

		public bool TryGetItem(string id, out Item item)
		{
			if (Banners.TryGetValue(id, out var value))
			{
				item = value;
				return true;
			}
			Dictionary<string, WeaponSkinItem>[] array = new Dictionary<string, WeaponSkinItem>[9] { Revolvers, AltRevolvers, Shotguns, AltShotguns, Nailguns, AltNailguns, Railcannons, Rockets, Presents };
			Dictionary<string, WeaponSkinItem>[] array2 = array;
			foreach (Dictionary<string, WeaponSkinItem> dictionary in array2)
			{
				if (dictionary.TryGetValue(id, out var value2))
				{
					item = value2;
					return true;
				}
			}
			item = null;
			return false;
		}
	}
	public class DatedRoomPool
	{
		public DateTime After;

		public string AssetPath;
	}
	public class ShopRotation
	{
		public List<string> ItemIds;

		public DateTime Start;

		public TimeSpan Length;

		[JsonIgnore]
		public DateTime End => Start + Length;
	}
}
namespace EndlessDelivery.Common.Communication.Scores
{
	public class OnlineScore
	{
		public ulong SteamId { get; set; }

		public Score Score { get; set; }

		public int Index { get; set; }

		public int CountryIndex { get; set; }

		public short Difficulty { get; set; }

		public DateTime Date { get; set; }
	}
	public class SubmitScoreData
	{
		public Score Score;

		public short Difficulty;

		public SubmitScoreData(Score score, short difficulty)
		{
			Score = score;
			Difficulty = difficulty;
		}
	}
}
namespace EndlessDelivery.Common.Achievements
{
	public class BestRoomAchievement : ServerSideAchievement
	{
		private string _id;

		private int _room;

		public override string Id => _id;

		public override bool ShouldGrant(OnlineScore score, OnlineScore bestScore, Score lifetimeStats)
		{
			return bestScore.Score.Rooms >= _room;
		}

		public BestRoomAchievement(string id, int room)
		{
			_id = id;
			_room = room;
		}
	}
	public class LifetimeRoomsAchievement : ServerSideAchievement
	{
		private string _id;

		private int _rooms;

		public override string Id => _id;

		public override bool ShouldGrant(OnlineScore score, OnlineScore bestScore, Score lifetimeStats)
		{
			return lifetimeStats.Rooms >= _rooms;
		}

		public LifetimeRoomsAchievement(string id, int rooms)
		{
			_id = id;
			_rooms = rooms;
		}
	}
	public class MoneyAchievement : ServerSideAchievement
	{
		private string _id;

		private float _money;

		public override string Id => _id;

		public override bool ShouldGrant(OnlineScore score, OnlineScore bestScore, Score lifetimeStats)
		{
			return (float)score.Score.MoneyGain > _money;
		}

		public MoneyAchievement(string id, int money)
		{
			_id = id;
			_money = money;
		}
	}
	public class PlaytimeAchievement : ServerSideAchievement
	{
		private string _id;

		private float _seconds;

		public override string Id => _id;

		public override bool ShouldGrant(OnlineScore score, OnlineScore bestScore, Score lifetimeStats)
		{
			return lifetimeStats.Time >= _seconds;
		}

		public PlaytimeAchievement(string id, TimeSpan time)
		{
			_id = id;
			_seconds = (float)time.TotalSeconds;
		}
	}
	public abstract class ServerSideAchievement
	{
		public static ServerSideAchievement[] AllAchievements = new ServerSideAchievement[10]
		{
			new BestRoomAchievement("first_place_ach", 60),
			new BestRoomAchievement("ach_top25", 45),
			new BestRoomAchievement("ach_top50", 30),
			new LifetimeRoomsAchievement("ach_100rooms", 100),
			new LifetimeRoomsAchievement("ach_500rooms", 500),
			new LifetimeRoomsAchievement("ach_1000rooms", 1000),
			new PlaytimeAchievement("ach_2hours", TimeSpan.FromHours(2.0)),
			new PlaytimeAchievement("ach_10hours", TimeSpan.FromHours(10.0)),
			new PlaytimeAchievement("ach_20hours", TimeSpan.FromHours(20.0)),
			new MoneyAchievement("ach_money1", 300)
		};

		public abstract string Id { get; }

		public abstract bool ShouldGrant(OnlineScore score, OnlineScore bestScore, Score lifetimeStats);
	}
}

plugins/Divine Delivery/EndlessDelivery.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using AtlasLib.Saving;
using AtlasLib.Utils;
using AtlasLib.Weapons;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using Discord;
using EndlessDelivery.Achievements;
using EndlessDelivery.Anticheat;
using EndlessDelivery.Api;
using EndlessDelivery.Api.Exceptions;
using EndlessDelivery.Api.Requests;
using EndlessDelivery.Assets;
using EndlessDelivery.Common;
using EndlessDelivery.Common.Achievements;
using EndlessDelivery.Common.Communication.Scores;
using EndlessDelivery.Common.ContentFile;
using EndlessDelivery.Common.Inventory.Items;
using EndlessDelivery.Components;
using EndlessDelivery.Config;
using EndlessDelivery.Cosmetics;
using EndlessDelivery.Cosmetics.Skins;
using EndlessDelivery.Gameplay;
using EndlessDelivery.Gameplay.EnemyGeneration;
using EndlessDelivery.Gameplay.Firework;
using EndlessDelivery.Gameplay.SpecialWaves;
using EndlessDelivery.Gameplay.Ward;
using EndlessDelivery.Online;
using EndlessDelivery.ScoreManagement;
using EndlessDelivery.UI;
using EndlessDelivery.Utils;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using ProjectProphet;
using Steamworks;
using Steamworks.Data;
using TMPro;
using UltraTweaker;
using UltraTweaker.Tweaks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.Audio;
using UnityEngine.Events;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.SceneManagement;
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.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("EndlessDelivery")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+85640807997ab32ab5c7711cdfca7086974d6d8e")]
[assembly: AssemblyProduct("EndlessDelivery")]
[assembly: AssemblyTitle("EndlessDelivery")]
[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 EndlessDelivery
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("waffle.ultrakill.christmasdelivery", "Divine Delivery", "2.2.2")]
	public class Plugin : BaseUnityPlugin
	{
		public static ManualLogSource Log;

		public const string Name = "Divine Delivery";

		public const string Version = "2.2.2";

		public const string Guid = "waffle.ultrakill.christmasdelivery";

		private void Start()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"Divine Delivery has started !!");
			AssetManager.LoadCatalog();
			AssetManager.LoadDataFile();
			OnlineFunctionality.Init();
			new Harmony("waffle.ultrakill.christmasdelivery").PatchAll();
		}
	}
}
namespace EndlessDelivery.Utils
{
	public enum Axis
	{
		X,
		Y,
		Z
	}
	public static class MathsExtensions
	{
		public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
		{
			Random rng = new Random();
			T[] elements = source.ToArray();
			for (int i = elements.Length - 1; i >= 0; i--)
			{
				int swapIndex = rng.Next(i + 1);
				yield return elements[swapIndex];
				elements[swapIndex] = elements[i];
			}
		}

		public static List<T> ShuffleAndToList<T>(this IEnumerable<T> source)
		{
			List<T> list = new List<T>();
			Random random = new Random();
			T[] array = source.ToArray();
			for (int num = array.Length - 1; num >= 0; num--)
			{
				int num2 = random.Next(num + 1);
				list.Add(array[num2]);
				array[num2] = array[num];
			}
			return list;
		}

		public static T Pick<T>(this T[] array)
		{
			if (array.Length == 0)
			{
				return (T)(object)null;
			}
			return array[Random.Range(0, array.Length)];
		}

		public static T Pick<T>(this List<T> list)
		{
			if (list.Count == 0)
			{
				return (T)(object)null;
			}
			return list[Random.Range(0, list.Count)];
		}

		public static Vector3 Only(this Vector3 vector, params Axis[] axes)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(axes.Contains(Axis.X) ? vector.x : 0f, axes.Contains(Axis.Y) ? vector.y : 0f, axes.Contains(Axis.Z) ? vector.z : 0f);
		}
	}
	public static class TimeUtils
	{
		public static string Formatted(this TimeSpan span)
		{
			return span.ToString("mm\\:ss\\:fff", new CultureInfo("en-US"));
		}
	}
}
namespace EndlessDelivery.UI
{
	[HarmonyPatch]
	public class AchievementHud : MonoSingleton<AchievementHud>
	{
		private static GameObject? s_asset;

		[SerializeField]
		private AudioSource? _soundEffect;

		[SerializeField]
		private GameObject? _holder;

		[SerializeField]
		private TMP_Text? _name;

		[SerializeField]
		private TMP_Text? _desc;

		[SerializeField]
		private Image? _icon;

		private bool _canShowNextAchievement = true;

		private Queue<Achievement> _achievements = new Queue<Achievement>();

		public void AddAchievement(Achievement achievement)
		{
			_achievements.Enqueue(achievement);
		}

		private void Update()
		{
			if (_canShowNextAchievement && _achievements.Count != 0)
			{
				((MonoBehaviour)this).StartCoroutine(ShowCoroutine(_achievements.Dequeue()));
				_canShowNextAchievement = false;
			}
		}

		private IEnumerator ShowCoroutine(Achievement achievement)
		{
			if ((Object)(object)_holder == (Object)null || (Object)(object)_name == (Object)null || (Object)(object)_desc == (Object)null || (Object)(object)_icon == (Object)null)
			{
				Plugin.Log.LogWarning((object)"AchievementHud has _holder, _name, _desc, or _icon null! Returning.");
				_canShowNextAchievement = true;
				yield break;
			}
			TMP_Text? name = _name;
			Cms? lastFetchedContent = OnlineFunctionality.LastFetchedContent;
			name.text = ((lastFetchedContent != null) ? lastFetchedContent.GetString(achievement.Name) : null) ?? achievement.Name;
			TMP_Text? desc = _desc;
			Cms? lastFetchedContent2 = OnlineFunctionality.LastFetchedContent;
			desc.text = ((lastFetchedContent2 != null) ? lastFetchedContent2.GetString(achievement.Description) : null) ?? achievement.Description;
			AsyncOperationHandle<Sprite> spriteLoad = Addressables.LoadAssetAsync<Sprite>((object)achievement.Icon.AddressablePath);
			yield return (object)new WaitUntil((Func<bool>)(() => spriteLoad.IsDone));
			AudioSource? soundEffect = _soundEffect;
			if (soundEffect != null)
			{
				soundEffect.Play();
			}
			_icon.sprite = spriteLoad.Result;
			_holder.SetActive(true);
			yield return (object)new WaitForSecondsRealtime(3f);
			Vector3 oldScale = _holder.transform.localScale;
			while (!_holder.transform.localScale.x.Equals(0f))
			{
				_holder.transform.localScale = Vector3.MoveTowards(_holder.transform.localScale, new Vector3(0f, _holder.transform.localScale.y), Time.unscaledDeltaTime * 20f);
				yield return null;
			}
			_holder.SetActive(false);
			_holder.transform.localScale = oldScale;
			_canShowNextAchievement = true;
		}

		[HarmonyPatch(typeof(CanvasController), "Awake")]
		[HarmonyPostfix]
		private static void AddSelf(CanvasController __instance)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if (s_asset == null)
			{
				s_asset = Addressables.LoadAssetAsync<GameObject>((object)"Assets/Delivery/Prefabs/HUD/Achievement UI.prefab").WaitForCompletion();
			}
			Object.Instantiate<GameObject>(s_asset, ((Component)__instance).transform);
		}
	}
	public class AchievementTerminal : MonoBehaviour
	{
		[SerializeField]
		private TMP_Text _achievementNameText;

		[SerializeField]
		private TMP_Text _achievementDescText;

		[SerializeField]
		private TMP_Text _achievementUnlocksText;

		[SerializeField]
		private GameObject _buttonTemplate;

		[SerializeField]
		private Transform _achievementHolder;

		private void Awake()
		{
			SetAchievement(null);
			((MonoBehaviour)this).StartCoroutine(PopulateAchievements());
		}

		private IEnumerator PopulateAchievements()
		{
			((Component)_achievementHolder).gameObject.SetActive(false);
			Task<Cms> cmsTask = OnlineFunctionality.GetContent();
			Task<List<OwnedAchievement>> achievementsTask = Users.GetAchievements(OnlineFunctionality.Context, SteamId.op_Implicit(SteamClient.SteamId));
			yield return (object)new WaitUntil((Func<bool>)(() => cmsTask.IsCompleted && achievementsTask.IsCompleted));
			Cms cms = cmsTask.Result;
			List<string> ownedAchievementIds = achievementsTask.Result.Select((OwnedAchievement x) => x.Id).ToList();
			foreach (Achievement achievement in cms.Achievements.Values.OrderBy((Achievement x) => !ownedAchievementIds.Contains(x.Id)))
			{
				if (!achievement.Disabled)
				{
					AddAchievement(achievement, ownedAchievementIds.Contains(achievement.Id));
				}
			}
			((Component)_achievementHolder).gameObject.SetActive(true);
		}

		private void AddAchievement(Achievement achievement, bool isOwned)
		{
			Object.Instantiate<GameObject>(_buttonTemplate, _achievementHolder).GetComponent<AchievementTerminalButton>().SetUp(this, achievement, isOwned);
		}

		public void SetAchievement(Achievement? achievement)
		{
			Cms cms = OnlineFunctionality.LastFetchedContent;
			_achievementNameText.text = ((achievement == null) ? "-" : cms.GetString(achievement.Name));
			_achievementDescText.text = ((achievement == null) ? "-" : (achievement.HideDetails ? cms.GetString("game_ui.hidden_achievement") : cms.GetString(achievement.Description)));
			if (achievement == null)
			{
				_achievementUnlocksText.text = "-";
				return;
			}
			List<Item> list = new List<Item>();
			string[] itemGrants = achievement.ItemGrants;
			Item item = default(Item);
			foreach (string text in itemGrants)
			{
				if (cms.TryGetItem(text, ref item))
				{
					list.Add(item);
				}
			}
			string @string = cms.GetString("game_ui.achievement_unlocks_nothing");
			string individualTemplate = cms.GetString("game_ui.achievement_unlock_individual");
			string arg = ((list.Count != 0) ? string.Join(", ", list.Select(delegate(Item x)
			{
				string arg2 = cms.GetString("category." + ((object)(StoreItemType)(ref x.Descriptor.Type)).ToString().ToLower()).ToLower();
				string string2 = cms.GetString(x.Descriptor.Name);
				return string.Format(individualTemplate, string2, arg2);
			})) : cms.GetString(@string));
			_achievementUnlocksText.text = string.Format(cms.GetString("game_ui.achievement_unlocks"), arg);
		}
	}
	public class AchievementTerminalButton : MonoBehaviour
	{
		[SerializeField]
		private Image _iconImage;

		[SerializeField]
		private Button _button;

		[SerializeField]
		private Image _buttonImage;

		[SerializeField]
		private Color _buttonAchievedColour;

		[SerializeField]
		private Color _buttonNotAchievedColour;

		private AchievementTerminal _parentTerminal;

		public void SetUp(AchievementTerminal parentTerminal, Achievement achievement, bool isOwned)
		{
			_parentTerminal = parentTerminal;
			((MonoBehaviour)parentTerminal).StartCoroutine(SetUpCoroutine(achievement, isOwned));
		}

		private IEnumerator SetUpCoroutine(Achievement achievement, bool isOwned)
		{
			Achievement achievement2 = achievement;
			((Component)this).gameObject.SetActive(false);
			AsyncOperationHandle<Sprite> spriteLoad = Addressables.LoadAssetAsync<Sprite>((object)achievement2.Icon.AddressablePath);
			yield return (object)new WaitUntil((Func<bool>)(() => spriteLoad.IsDone));
			_iconImage.sprite = spriteLoad.Result;
			((Graphic)_buttonImage).color = (isOwned ? _buttonAchievedColour : _buttonNotAchievedColour);
			((UnityEvent)_button.onClick).AddListener((UnityAction)delegate
			{
				_parentTerminal.SetAchievement(achievement2);
			});
			((Component)this).gameObject.SetActive(true);
		}
	}
	public class AdventCalendar : MonoBehaviour
	{
		private static readonly string[] s_buttonOrder = new string[25]
		{
			"day15_2024", "day16_2024", "day4_2024", "day25_2024", "day8_2024", "day22_2024", "day24_2024", "day18_2024", "day10_2024", "day20_2024",
			"day6_2024", "day13_2024", "day23_2024", "day3_2024", "day17_2024", "day7_2024", "day19_2024", "day14_2024", "day12_2024", "day1_2024",
			"day5_2024", "day9_2024", "day21_2024", "day2_2024", "day11_2024"
		};

		[SerializeField]
		private GameObject _templateButton;

		[SerializeField]
		private Transform _buttonHolder;

		[SerializeField]
		private GameObject _claimPage;

		[SerializeField]
		private Image _iconImage;

		[SerializeField]
		private TMP_Text _nameTitle;

		[SerializeField]
		private TMP_Text _descriptionText;

		[SerializeField]
		private TMP_Text _subtitleText;

		[SerializeField]
		private Button _claimButton;

		[SerializeField]
		private TMP_Text _claimButtonText;

		[SerializeField]
		private TMP_Text _timeRemainingText;

		[SerializeField]
		private MoneyCounter _moneyCounter;

		private List<string> _ownedDays = new List<string>();

		private List<GameObject> _buttons = new List<GameObject>();

		private string _timeRemainingString = "{0}";

		private DateTime _endTime;

		private Item? _selectedItem;

		private bool _rewardIsToday;

		private int _cachedCurrencyAmount;

		public void Claim()
		{
			CalendarReward todayReward = OnlineFunctionality.LastFetchedContent.CurrentCalendarReward;
			if (_rewardIsToday)
			{
				_ownedDays.Add(todayReward.Id);
			}
			_claimButtonText.text = OnlineFunctionality.LastFetchedContent.GetString("game_ui.calendar_claimed");
			((Selectable)_claimButton).interactable = false;
			Task.Run(async delegate
			{
				if (_rewardIsToday)
				{
					await Items.ClaimDailyReward(OnlineFunctionality.Context);
					if (todayReward.HasCurrency)
					{
						_cachedCurrencyAmount += todayReward.CurrencyAmount;
					}
				}
				else
				{
					Plugin.Log.LogInfo((object)("buying item " + _selectedItem.Descriptor.Id));
					try
					{
						_cachedCurrencyAmount -= _selectedItem.Descriptor.ShopPrice;
						await Items.BuyItem(OnlineFunctionality.Context, _selectedItem.Descriptor.Id);
					}
					catch (Exception ex2)
					{
						Exception ex = ex2;
						Plugin.Log.LogError((object)ex.ToString());
					}
				}
				await CosmeticManager.FetchLoadout();
				_moneyCounter.RefreshMoney(_cachedCurrencyAmount);
			});
		}

		public void EnableClaimUi(string dayId)
		{
			((MonoBehaviour)this).StartCoroutine(EnableClaimUiCoroutine(dayId));
		}

		private IEnumerator EnableClaimUiCoroutine(string dayId)
		{
			Cms cms = OnlineFunctionality.LastFetchedContent;
			CalendarReward reward = cms.CalendarRewards[dayId];
			if ((!cms.TryGetItem(reward.ItemId, ref _selectedItem) || _selectedItem == null) && reward.HasItem)
			{
				Plugin.Log.LogWarning((object)(reward.ItemId + " has no item despite HasItem being true, calendar not showing (how has this happened)"));
				yield break;
			}
			AsyncOperationHandle<Sprite> loadIcon = Addressables.LoadAssetAsync<Sprite>((object)reward.Icon.AddressablePath);
			Task<int> getCurrency = Users.GetCurrencyAmount(OnlineFunctionality.Context);
			yield return (object)new WaitUntil((Func<bool>)(() => loadIcon.IsDone && getCurrency.IsCompleted));
			_cachedCurrencyAmount = getCurrency.Result;
			_moneyCounter.SetValue(_cachedCurrencyAmount);
			_iconImage.sprite = loadIcon.Result;
			_nameTitle.text = cms.GetString(reward.Name);
			_descriptionText.text = cms.GetString(reward.Description);
			_subtitleText.text = cms.GetString(reward.Subtitle);
			bool isClaimed = _ownedDays.Contains(dayId) || (_selectedItem != null && CosmeticManager.AllOwned.Contains(_selectedItem.Descriptor.Id));
			_rewardIsToday = dayId == cms.CurrentCalendarReward?.Id;
			((Selectable)_claimButton).interactable = !isClaimed && (_rewardIsToday || (reward.HasItem && _selectedItem.Descriptor.ShopPrice <= _cachedCurrencyAmount));
			string missedString = (reward.HasItem ? string.Format(cms.GetString("game_ui.calendar_buy"), _selectedItem.Descriptor.ShopPrice) : cms.GetString("game_ui.calendar_missed"));
			string unclaimedString = (_rewardIsToday ? "game_ui.calendar_unclaimed" : missedString);
			_claimButtonText.text = cms.GetString(isClaimed ? "game_ui.calendar_claimed" : unclaimedString);
			_claimPage.SetActive(true);
		}

		private void Awake()
		{
			_timeRemainingString = OnlineFunctionality.LastFetchedContent.GetString("game_ui.shop_remaining_time");
			((MonoBehaviour)this).StartCoroutine(Refresh());
		}

		private void FixedUpdate()
		{
			_timeRemainingText.text = string.Format(_timeRemainingString, DdUtils.ToWordString(_endTime - DateTime.UtcNow));
			if (DateTime.UtcNow > _endTime)
			{
				((MonoBehaviour)this).StartCoroutine(Refresh());
				_endTime = DateTime.MaxValue;
			}
		}

		private IEnumerator Refresh()
		{
			CalendarReward next = OnlineFunctionality.LastFetchedContent.CurrentCalendarReward;
			bool hasNextDay = next != null && !next.IsLastDay;
			_endTime = ((!hasNextDay) ? DateTime.MaxValue : (next.Date + TimeSpan.FromDays(1.0)));
			((Component)_timeRemainingText).gameObject.SetActive(hasNextDay);
			foreach (GameObject oldButton in _buttons)
			{
				Object.Destroy((Object)(object)oldButton);
			}
			Task<Cms> contentTask = OnlineFunctionality.GetContent();
			yield return (object)new WaitUntil((Func<bool>)(() => contentTask.IsCompleted));
			((MonoBehaviour)this).StartCoroutine(CreateButtons());
		}

		private IEnumerator CreateButtons()
		{
			Task<List<string>> getClaimedTask = Items.GetClaimedDailyRewards(OnlineFunctionality.Context);
			yield return (object)new WaitUntil((Func<bool>)(() => getClaimedTask.IsCompleted));
			_ownedDays = getClaimedTask.Result;
			string[] array = s_buttonOrder;
			foreach (string dayId in array)
			{
				if (!OnlineFunctionality.LastFetchedContent.CalendarRewards.ContainsKey(dayId))
				{
					Plugin.Log.LogWarning((object)("Missing day ID " + dayId));
					continue;
				}
				GameObject button = Object.Instantiate<GameObject>(_templateButton, _buttonHolder);
				_buttons.Add(button);
				button.GetComponent<AdventCalendarButton>().SetUp(this, OnlineFunctionality.LastFetchedContent.CalendarRewards[dayId]);
			}
		}
	}
	public class AdventCalendarButton : MonoBehaviour
	{
		[SerializeField]
		private TMP_Text _numberText;

		[SerializeField]
		private Button _button;

		[SerializeField]
		private Image _image;

		[SerializeField]
		private Color _todayColour;

		[SerializeField]
		private Color _beforeTodayColour;

		[SerializeField]
		private Color _afterTodayColour;

		public void SetUp(AdventCalendar parent, CalendarReward reward)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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)
			AdventCalendar parent2 = parent;
			CalendarReward reward2 = reward;
			_numberText.text = reward2.Date.Day.ToString();
			((UnityEvent)_button.onClick).AddListener((UnityAction)delegate
			{
				parent2.EnableClaimUi(reward2.Id);
			});
			Color color = _todayColour;
			if (reward2.Date.Date < DateTime.UtcNow.Date)
			{
				color = _beforeTodayColour;
			}
			if (reward2.Date.Date > DateTime.UtcNow.Date)
			{
				((Selectable)_button).interactable = false;
				color = _afterTodayColour;
			}
			((Graphic)_image).color = color;
		}
	}
	[HarmonyPatch]
	public class AltPresentHud : MonoBehaviour
	{
		public TMP_Text[] PresentTexts;

		public TMP_Text TimerText;

		public TMP_Text RoomText;

		public Color TimerColour;

		public Color TimerDangerColour;

		public void Update()
		{
			//IL_008c: 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)
			if (MonoSingleton<GameManager>.Instance.GameStarted)
			{
				TimerText.text = TimeSpan.FromSeconds(MonoSingleton<GameManager>.Instance.TimeLeft).Formatted();
				RoomText.text = MonoSingleton<GameManager>.Instance.RoomsComplete.ToString();
				if (MonoSingleton<GameManager>.Instance.TimeLeft < 10f)
				{
					((Graphic)TimerText).color = TimerDangerColour;
				}
				else
				{
					((Graphic)TimerText).color = TimerColour;
				}
				int num = 0;
				Room currentRoom = MonoSingleton<GameManager>.Instance.CurrentRoom;
				TMP_Text[] presentTexts = PresentTexts;
				foreach (TMP_Text val in presentTexts)
				{
					val.text = $"{currentRoom.AmountDelivered[(WeaponVariant)num]}/{currentRoom.PresentColourAmounts[num]}";
					num++;
				}
			}
		}

		[HarmonyPatch(typeof(HudController), "Start")]
		[HarmonyPostfix]
		private static void AddSelf(HudController __instance)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (__instance.altHud && !MapInfoBase.InstanceAnyType.hideStockHUD && AssetManager.InSceneFromThisMod)
			{
				GameObject val = Addressables.LoadAssetAsync<GameObject>((object)"Assets/Delivery/Prefabs/HUD/Classic Present Hud.prefab").WaitForCompletion();
				Object.Instantiate<GameObject>(val, UnityUtils.GetChild(((Component)__instance).gameObject, "Filler").transform);
			}
		}
	}
	public class CheatsFoundScreen : MonoBehaviour
	{
		[SerializeField]
		private TMP_Text _reasonsText;

		private void Awake()
		{
			if (!EndlessDelivery.Anticheat.Anticheat.HasIllegalMods(out List<string> reasons))
			{
				((Component)this).gameObject.SetActive(false);
				return;
			}
			DisablePlayer();
			_reasonsText.text = string.Join("; ", reasons);
			((Component)this).gameObject.SetActive(true);
		}

		private void Update()
		{
			Cursor.visible = true;
			Cursor.lockState = (CursorLockMode)2;
			((Behaviour)MonoSingleton<NewMovement>.Instance).enabled = false;
			((Behaviour)MonoSingleton<GunControl>.Instance).enabled = false;
			((Behaviour)MonoSingleton<FistControl>.Instance).enabled = false;
			Time.timeScale = 0f;
		}

		private void DisablePlayer()
		{
			//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: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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)
			//IL_0039: Expected O, but got Unknown
			GameStateManager.Instance.RegisterState(new GameState("pause_cheatscreen", (GameObject[])(object)new GameObject[1] { ((Component)this).gameObject })
			{
				cursorLock = (LockMode)2,
				cameraInputLock = (LockMode)1,
				playerInputLock = (LockMode)1
			});
			((Behaviour)MonoSingleton<NewMovement>.Instance).enabled = false;
			((Behaviour)MonoSingleton<GunControl>.Instance).enabled = false;
			((Behaviour)MonoSingleton<FistControl>.Instance).enabled = false;
			Time.timeScale = 0f;
		}

		public void ReenablePlayer()
		{
			((Behaviour)MonoSingleton<NewMovement>.Instance).enabled = true;
			((Behaviour)MonoSingleton<GunControl>.Instance).enabled = true;
			((Behaviour)MonoSingleton<FistControl>.Instance).enabled = true;
			MonoSingleton<TimeController>.Instance.RestoreTime();
		}
	}
	public class ColourSetter : MonoBehaviour
	{
		public int Colour;

		private void Start()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			Color colour = ConfigFile.Instance.Data.GetColour(Colour);
			Text val = default(Text);
			if (((Component)this).TryGetComponent<Text>(ref val))
			{
				((Graphic)val).color = colour;
			}
			TMP_Text val2 = default(TMP_Text);
			if (((Component)this).TryGetComponent<TMP_Text>(ref val2))
			{
				((Graphic)val2).color = colour;
			}
			Image val3 = default(Image);
			if (((Component)this).TryGetComponent<Image>(ref val3))
			{
				((Graphic)val3).color = colour;
			}
		}
	}
	[HarmonyPatch]
	public class DeliveryButton
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__0_0;

			internal void <AddButton>b__0_0()
			{
				((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(LoadWhenLogged());
			}
		}

		[HarmonyPatch(typeof(CanvasController), "Awake")]
		[HarmonyPostfix]
		private static void AddButton(CanvasController __instance)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Expected O, but got Unknown
			GameObject child = UnityUtils.GetChild(((Component)__instance).gameObject, "Chapter Select");
			if ((Object)(object)child == (Object)null)
			{
				return;
			}
			GameObject child2 = UnityUtils.GetChild(child, "The Cyber Grind");
			RectTransform component = child2.GetComponent<RectTransform>();
			component.sizeDelta -= new Vector2(55f, 0f);
			((Transform)component).position = ((Transform)component).position - new Vector3(27.5f, 0f, 0f);
			GameObject val = Object.Instantiate<GameObject>(Addressables.LoadAssetAsync<GameObject>((object)"Assets/Delivery/Prefabs/HUD/Jolly Chapter Select Button.prefab").WaitForCompletion(), child.transform);
			ButtonClickedEvent onClick = val.GetComponent<Button>().onClick;
			object obj = <>c.<>9__0_0;
			if (obj == null)
			{
				UnityAction val2 = delegate
				{
					((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(LoadWhenLogged());
				};
				<>c.<>9__0_0 = val2;
				obj = (object)val2;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj);
		}

		private static IEnumerator LoadWhenLogged()
		{
			Task<bool> isOnlineTask = Api.ServerOnline(OnlineFunctionality.Context);
			yield return (object)new WaitUntil((Func<bool>)(() => isOnlineTask.IsCompleted));
			yield return (object)new WaitUntil((Func<bool>)(() => OnlineFunctionality.LoggedIn || !isOnlineTask.Result));
			AssetManager.LoadSceneUnsanitzed("Assets/Delivery/Scenes/Game Scene.unity");
		}
	}
	[HarmonyPatch]
	public class EndScreen : MonoSingleton<EndScreen>
	{
		public GameObject[] ToAppear;

		public GameObject AudioObject;

		public Image HighscoreFlash;

		public float Delay = 0.25f;

		public float SkippingDelay = 0.05f;

		[Space(10f)]
		public ReachValueText Rooms;

		public ReachValueText Kills;

		public ReachValueText Deliveries;

		public ReachValueText TimeElapsed;

		[Space(10f)]
		public Text BestRooms;

		public Text BestKills;

		public Text BestDeliveries;

		public Text BestTimeElapsed;

		[Space(10f)]
		public ReachValueText MoneyGainText;

		[Space(10f)]
		public GameObject Leaderboard;

		public GameObject EverythingButLeaderboard;

		[HideInInspector]
		public bool NewBest;

		[HideInInspector]
		public ReachValueText CurrentText;

		[HideInInspector]
		public Score PreviousHighscore;

		private int _currentIndex;

		private float _timeSinceComplete;

		private bool _appearedSelf;

		private bool _complete;

		private bool _leaderboardShown;

		public bool Skipping => MonoSingleton<InputManager>.Instance.InputSource.Fire1.WasPerformedThisFrame || MonoSingleton<InputManager>.Instance.InputSource.Jump.WasPerformedThisFrame;

		private void Awake()
		{
			GameObject[] toAppear = ToAppear;
			foreach (GameObject val in toAppear)
			{
				val.SetActive(false);
			}
		}

		public void Appear()
		{
			SetPanelValues(MonoSingleton<GameManager>.Instance.CurrentScore, Rooms, Kills, Deliveries, TimeElapsed);
			SetPanelValues(NewBest ? PreviousHighscore : ScoreManager.CurrentDifficultyHighscore, BestRooms, BestKills, BestDeliveries, BestTimeElapsed);
			MoneyGainText.Target = MonoSingleton<GameManager>.Instance.CurrentScore.MoneyGain;
			((MonoBehaviour)this).StartCoroutine(AppearCoroutine());
		}

		private IEnumerator AppearCoroutine()
		{
			TimeController timeController = MonoSingleton<TimeController>.Instance;
			timeController.controlTimeScale = false;
			while (timeController.timeScale > 0f)
			{
				timeController.timeScale = Mathf.MoveTowards(timeController.timeScale, 0f, Time.unscaledDeltaTime * (timeController.timeScale + 0.01f));
				Time.timeScale = timeController.timeScale * timeController.timeScaleModifier;
				MonoSingleton<AudioMixerController>.Instance.allSound.SetFloat("allPitch", timeController.timeScale);
				MonoSingleton<AudioMixerController>.Instance.allSound.SetFloat("allVolume", 0.5f + timeController.timeScale / 2f);
				MonoSingleton<AudioMixerController>.Instance.musicSound.SetFloat("allPitch", timeController.timeScale);
				MonoSingleton<MusicManager>.Instance.volume = 0.5f + timeController.timeScale / 2f;
				yield return null;
			}
			ShowNext();
			_appearedSelf = true;
			MonoSingleton<MusicManager>.Instance.forcedOff = true;
			MonoSingleton<MusicManager>.Instance.StopMusic();
			AudioObject.SetActive(true);
		}

		private void SetPanelValues(Score score, ReachValueText rooms, ReachValueText kills, ReachValueText deliveries, ReachValueText time)
		{
			rooms.Target = score.Rooms;
			kills.Target = score.Kills;
			deliveries.Target = score.Deliveries;
			time.Target = score.Time;
		}

		private void SetPanelValues(Score score, Text rooms, Text kills, Text deliveries, Text time)
		{
			int rooms2 = score.Rooms;
			rooms.text = rooms2.ToString();
			rooms2 = score.Kills;
			kills.text = rooms2.ToString();
			rooms2 = score.Deliveries;
			deliveries.text = rooms2.ToString();
			time.text = TimeSpan.FromSeconds(score.Time).Formatted();
		}

		private void Update()
		{
			if (_appearedSelf)
			{
				ReachValueText currentText = CurrentText;
				if (currentText == null || currentText.Done)
				{
					_timeSinceComplete += Time.unscaledDeltaTime;
				}
				if ((_timeSinceComplete >= ((!Skipping) ? Delay : SkippingDelay) && _currentIndex != ToAppear.Length) || Skipping)
				{
					ShowNext();
					_timeSinceComplete = 0f;
				}
			}
		}

		private void ShowNext()
		{
			if (_currentIndex == ToAppear.Length)
			{
				if (!_leaderboardShown)
				{
					Leaderboard.SetActive(true);
					EverythingButLeaderboard.SetActive(false);
					_leaderboardShown = true;
				}
				else
				{
					MonoSingleton<NewMovement>.Instance.hp = 0;
					_complete = true;
				}
			}
			else
			{
				ToAppear[_currentIndex++].SetActive(true);
			}
		}

		public void DoFlashIfApplicable()
		{
			if (NewBest)
			{
				SetPanelValues(ScoreManager.CurrentDifficultyHighscore, BestRooms, BestKills, BestDeliveries, BestTimeElapsed);
				((MonoBehaviour)this).StartCoroutine(DoHighscoreFlash());
			}
		}

		private IEnumerator DoHighscoreFlash()
		{
			((Graphic)HighscoreFlash).color = new Color(1f, 1f, 1f, 1f);
			((Component)HighscoreFlash).GetComponent<AudioSource>().Play();
			while (((Graphic)HighscoreFlash).color.a != 0f)
			{
				((Graphic)HighscoreFlash).color = new Color(1f, 1f, 1f, Mathf.MoveTowards(((Graphic)HighscoreFlash).color.a, 0f, Time.unscaledDeltaTime));
				yield return null;
			}
		}

		[HarmonyPatch(typeof(CanvasController), "Awake")]
		[HarmonyPostfix]
		private static void CreateSelf()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			Object.Instantiate<GameObject>(Addressables.LoadAssetAsync<GameObject>((object)"Assets/Delivery/Prefabs/HUD/Delivery End Screen.prefab").WaitForCompletion());
		}
	}
	public class EndScreenLeaderboards : MonoBehaviour
	{
		public Text[] ConnectingToServerText;

		public Transform TopLeaderboardContainer;

		public Transform NearbyLeaderboardContainer;

		public GameObject EntryTemplate;

		public void OnEnable()
		{
			DoStuff();
		}

		private async Task DoStuff()
		{
			if (MonoSingleton<PrefsManager>.Instance.GetInt("difficulty", 0) < 3)
			{
				Text[] connectingToServerText = ConnectingToServerText;
				foreach (Text text3 in connectingToServerText)
				{
					text3.text = "LEADERBOARDS ARE ONLY ON VIOLENT AND ABOVE";
				}
				return;
			}
			if (!(await Api.ServerOnline(OnlineFunctionality.Context)))
			{
				Text[] connectingToServerText2 = ConnectingToServerText;
				foreach (Text text2 in connectingToServerText2)
				{
					text2.text = "FAILED TO CONNECT :^(";
				}
				return;
			}
			int ownPosition = await Scores.GetLeaderboardPosition(OnlineFunctionality.Context, SteamId.op_Implicit(SteamClient.SteamId));
			OnlineScore[] nearScores = await Scores.GetScoreRange(OnlineFunctionality.Context, Mathf.Max(ownPosition - 5, 0), 10);
			OnlineScore[] topScores = await Scores.GetScoreRange(OnlineFunctionality.Context, 0, 10);
			OnlineScore[] array = nearScores;
			foreach (OnlineScore scoreResult in array)
			{
				Object.Instantiate<GameObject>(EntryTemplate, NearbyLeaderboardContainer).GetComponent<LeaderboardEntry>().SetValuesAndEnable((MonoBehaviour)(object)this, scoreResult);
			}
			OnlineScore[] array2 = topScores;
			foreach (OnlineScore scoreResult2 in array2)
			{
				Object.Instantiate<GameObject>(EntryTemplate, TopLeaderboardContainer).GetComponent<LeaderboardEntry>().SetValuesAndEnable((MonoBehaviour)(object)this, scoreResult2);
			}
			Text[] connectingToServerText3 = ConnectingToServerText;
			foreach (Text text in connectingToServerText3)
			{
				((Component)text).gameObject.SetActive(false);
			}
		}
	}
	public class JollyTerminal : MonoBehaviour
	{
		public GameObject[] DisableIfNotOnHighscoreDifficulty;

		private void OnEnable()
		{
			bool active = MonoSingleton<PrefsManager>.Instance.GetInt("difficulty", 0) >= 3;
			GameObject[] disableIfNotOnHighscoreDifficulty = DisableIfNotOnHighscoreDifficulty;
			foreach (GameObject val in disableIfNotOnHighscoreDifficulty)
			{
				val.SetActive(active);
			}
		}
	}
	public class JollyTerminalLeaderboards : MonoBehaviour
	{
		public Button[] PageButtons;

		public Button JumpToSelfButton;

		public LeaderboardEntry[] Entries;

		public LeaderboardEntry OwnEntry;

		public TMP_Text PageText;

		private OnlineScore[] _pageScores;

		private int _page;

		private int? _pageAmount = null;

		private Coroutine? _lastRefresh;

		private OnlineScore? _ownScore;

		private async Task SetStuff()
		{
			if (await Api.ServerOnline(OnlineFunctionality.Context))
			{
				_pageAmount = Mathf.CeilToInt((float)(await Scores.GetLeaderboardLength(OnlineFunctionality.Context)) / (float)Entries.Length);
				RefreshPageText();
				try
				{
					_ownScore = await Scores.GetLeaderboardScore(OnlineFunctionality.Context, SteamId.op_Implicit(SteamClient.SteamId));
				}
				catch (NotFoundException)
				{
					_ownScore = null;
				}
				OwnEntry.SetValuesAndEnable((MonoBehaviour)(object)this, _ownScore);
				if (_ownScore == null)
				{
					((Selectable)JumpToSelfButton).interactable = false;
				}
			}
		}

		public void OnEnable()
		{
			LeaderboardEntry[] entries = Entries;
			foreach (LeaderboardEntry leaderboardEntry in entries)
			{
				((Component)leaderboardEntry).gameObject.SetActive(false);
			}
			_lastRefresh = ((MonoBehaviour)this).StartCoroutine(RefreshPage());
		}

		public void ScrollPage(int amount)
		{
			if (_page + amount >= 0 && !(_page + amount > _pageAmount - 1))
			{
				RefreshPageText();
				SetPage(_page + amount);
			}
		}

		public void SetPage(int page)
		{
			_page = page;
			_lastRefresh = ((MonoBehaviour)this).StartCoroutine(RefreshPage());
		}

		private void RefreshPageText()
		{
			PageText.text = _page + 1 + " / " + ((!_pageAmount.HasValue) ? "-" : _pageAmount.ToString());
		}

		public void JumpToSelf()
		{
			if (_ownScore == null)
			{
				Plugin.Log.LogWarning((object)"JumpToSelf with null _ownScore - should be impossible");
				return;
			}
			int page = Mathf.FloorToInt((float)_ownScore.Index / (float)Entries.Length);
			SetPage(page);
		}

		private static async Task<OnlineScore[]> GetPage(int pageIndex, int pageSize)
		{
			int scoreCount = await Scores.GetLeaderboardLength(OnlineFunctionality.Context);
			int startIndex = pageIndex * pageSize;
			int amount = Mathf.Min(scoreCount - startIndex, pageSize);
			return await Scores.GetScoreRange(OnlineFunctionality.Context, pageIndex * pageSize, amount);
		}

		public void OpenWebsite()
		{
			Application.OpenURL(OnlineFunctionality.LastFetchedContent.GetString("constants.website"));
		}

		public void JoinDiscord()
		{
			Application.OpenURL(OnlineFunctionality.LastFetchedContent.GetString("constants.discord"));
		}

		private IEnumerator RefreshPage()
		{
			if (_lastRefresh != null)
			{
				((MonoBehaviour)this).StopCoroutine(_lastRefresh);
			}
			Task<bool> onlineTask = Api.ServerOnline(OnlineFunctionality.Context);
			yield return (object)new WaitUntil((Func<bool>)(() => onlineTask.IsCompleted));
			if (!onlineTask.Result)
			{
				MonoSingleton<HudMessageReceiver>.Instance.SendHudMessage("Server offline!", "", "", 0, false);
				((Component)this).gameObject.SetActive(false);
				yield break;
			}
			bool jumpToSelfWasEnabled = ((Selectable)JumpToSelfButton).interactable;
			Button[] pageButtons = PageButtons;
			foreach (Button button in pageButtons)
			{
				((Selectable)button).interactable = false;
			}
			Task<OnlineScore[]> scoreTask = GetPage(_page, Entries.Length);
			Task setStuff = SetStuff();
			yield return (object)new WaitUntil((Func<bool>)(() => scoreTask.IsCompleted && setStuff.IsCompleted));
			_pageScores = scoreTask.Result;
			for (int i = 0; i < Entries.Length; i++)
			{
				if (i < _pageScores.Length)
				{
					Entries[i].SetValuesAndEnable((MonoBehaviour)(object)this, _pageScores[i]);
				}
				else
				{
					((Component)Entries[i]).gameObject.SetActive(false);
				}
			}
			Button[] pageButtons2 = PageButtons;
			foreach (Button button2 in pageButtons2)
			{
				((Selectable)button2).interactable = true;
			}
			if (!jumpToSelfWasEnabled)
			{
				((Selectable)JumpToSelfButton).interactable = jumpToSelfWasEnabled;
			}
		}
	}
	public class JollyTerminalShop : MonoBehaviour
	{
		[SerializeField]
		private GameObject _templatePanel;

		[SerializeField]
		private Transform _panelHolder;

		[SerializeField]
		private AudioSource _buySound;

		[SerializeField]
		private AudioSource _buyError;

		[SerializeField]
		private TMP_Text _timeRemainingText;

		[SerializeField]
		private MoneyCounter _moneyCounter;

		private List<ShopItemPanel> _panels = new List<ShopItemPanel>();

		private bool _hasInitialized = false;

		private int _totalMoney = 0;

		private DateTime _endTime;

		private string _timeRemainingString = "{0}";

		private void OnEnable()
		{
			((MonoBehaviour)this).StartCoroutine(InitializeIfOnline());
		}

		private void FixedUpdate()
		{
			if (!(_endTime == default(DateTime)))
			{
				_timeRemainingText.text = string.Format(_timeRemainingString, DdUtils.ToWordString(_endTime - DateTime.UtcNow));
				if (DateTime.UtcNow > _endTime)
				{
					((MonoBehaviour)this).StartCoroutine(RefreshShop());
					_endTime = DateTime.MaxValue;
				}
			}
		}

		private IEnumerator InitializeIfOnline()
		{
			Task<bool> onlineTask = Api.ServerOnline(OnlineFunctionality.Context);
			yield return (object)new WaitUntil((Func<bool>)(() => onlineTask.IsCompleted));
			if (!onlineTask.Result)
			{
				MonoSingleton<HudMessageReceiver>.Instance.SendHudMessage("Server offline!", "", "", 0, false);
				yield break;
			}
			((MonoBehaviour)this).StartCoroutine(SetInitialMoneyCoroutine());
			((MonoBehaviour)this).StartCoroutine(RefreshShop());
		}

		private IEnumerator RefreshShop()
		{
			foreach (ShopItemPanel panel in _panels)
			{
				if (!((Object)(object)panel == (Object)null) && !((Object)(object)((Component)panel).gameObject == (Object)null))
				{
					Object.Destroy((Object)(object)((Component)panel).gameObject);
				}
			}
			_panels.Clear();
			Task<ShopRotation> shopTask = Items.GetActiveShop(OnlineFunctionality.Context);
			Task<Cms> cmsTask = OnlineFunctionality.GetContent();
			yield return (object)new WaitUntil((Func<bool>)(() => shopTask.IsCompleted && cmsTask.IsCompleted));
			_timeRemainingString = cmsTask.Result.GetString("game_ui.shop_remaining_time");
			_endTime = shopTask.Result.End;
			Item item = default(Item);
			foreach (string itemId in shopTask.Result.ItemIds)
			{
				if (!cmsTask.Result.TryGetItem(itemId, ref item))
				{
					Plugin.Log.LogWarning((object)("Shop rotation contains missing item: " + item.Descriptor.Id));
					continue;
				}
				AddItem(item.Descriptor);
				item = null;
			}
		}

		private IEnumerator SetInitialMoneyCoroutine()
		{
			Task<int> moneyTask = Users.GetCurrencyAmount(OnlineFunctionality.Context);
			yield return (object)new WaitUntil((Func<bool>)(() => moneyTask.IsCompleted));
			_totalMoney = moneyTask.Result;
			_moneyCounter.SetValue(moneyTask.Result);
			_hasInitialized = true;
		}

		private void AddItem(ItemDescriptor item)
		{
			GameObject val = Object.Instantiate<GameObject>(_templatePanel, _panelHolder);
			val.SetActive(false);
			ShopItemPanel component = val.GetComponent<ShopItemPanel>();
			_panels.Add(component);
			component.SetUp(this, item);
		}

		public void BuyItem(ItemDescriptor item)
		{
			if (item.ShopPrice > _totalMoney)
			{
				_buyError.Play();
				return;
			}
			foreach (ShopItemPanel panel in _panels)
			{
				panel.Disable();
			}
			((MonoBehaviour)this).StartCoroutine(BuyItemCoroutine(item));
		}

		private IEnumerator BuyItemCoroutine(ItemDescriptor item)
		{
			Task buyTask = Items.BuyItem(OnlineFunctionality.Context, item.Id);
			Task loadoutTask = CosmeticManager.FetchLoadout();
			yield return (object)new WaitUntil((Func<bool>)(() => buyTask.IsCompleted && loadoutTask.IsCompleted));
			Task refreshTask = CosmeticManager.FetchLoadout();
			yield return (object)new WaitUntil((Func<bool>)(() => refreshTask.IsCompleted));
			_buySound.Play();
			_totalMoney -= item.ShopPrice;
			_moneyCounter.RefreshMoney(_totalMoney);
			foreach (ShopItemPanel itemPanel in _panels)
			{
				itemPanel.Enable();
			}
		}
	}
	public class JollyTerminalStartPickButton : MonoBehaviour
	{
		[SerializeField]
		private Button _button;

		[SerializeField]
		private TMP_Text _text;

		public void Setup(JollyTerminalStartPicker picker, int startWave)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			JollyTerminalStartPicker picker2 = picker;
			StartTimes.StartTime currentTimes = ((SaveFile<StartTimes>)(object)StartTimes.Instance).Data.CurrentTimes;
			_text.text = startWave.ToString();
			if (!currentTimes.UnlockedStartTimes.Contains(startWave))
			{
				((Selectable)_button).interactable = false;
				return;
			}
			((UnityEvent)_button.onClick).AddListener((UnityAction)delegate
			{
				picker2.SetWave(startWave);
			});
		}
	}
	public class JollyTerminalStartPicker : MonoBehaviour
	{
		[SerializeField]
		private TMP_Text? _timeDisplayText;

		[SerializeField]
		private GameObject? _buttonPrefab;

		[SerializeField]
		private Transform? _buttonHolder;

		private bool _hasPopulated;

		private void OnEnable()
		{
			if (!_hasPopulated)
			{
				Populate();
				SetWave(((SaveFile<StartTimes>)(object)StartTimes.Instance).Data.CurrentTimes.SelectedWave);
			}
		}

		private void Populate()
		{
			if ((Object)(object)_buttonPrefab == (Object)null || (Object)(object)_buttonHolder == (Object)null)
			{
				throw new Exception("StartPicker Button prefab or button holder is null");
			}
			int[] startableWaves = StartTimes.StartTime.StartableWaves;
			foreach (int startWave in startableWaves)
			{
				Object.Instantiate<GameObject>(_buttonPrefab, _buttonHolder).GetComponent<JollyTerminalStartPickButton>().Setup(this, startWave);
			}
			_hasPopulated = true;
		}

		public void SetWave(int wave)
		{
			StartTimes.StartTime currentTimes = ((SaveFile<StartTimes>)(object)StartTimes.Instance).Data.CurrentTimes;
			currentTimes.SelectedWave = wave;
			if ((Object)(object)_timeDisplayText == (Object)null)
			{
				Plugin.Log.LogWarning((object)"Time display text on start picker is null");
				return;
			}
			string arg = TimeSpan.FromSeconds(currentTimes.GetRoomTime(wave)).ToString("mm\\:ss\\.fff", new CultureInfo("en-US"));
			_timeDisplayText.text = $"<size=20><color=orange>ROOM {wave}\n<size=15><color=#999999>TIME: {arg}";
		}
	}
	public class LeaderboardEntry : MonoBehaviour
	{
		[Header("All monobehaviours here should implement IText")]
		public MonoBehaviour RankNumber;

		public MonoBehaviour Username;

		public MonoBehaviour Rooms;

		public MonoBehaviour Difficulty;

		public Image ProfileActual;

		public Image Banner;

		[SerializeField]
		private Sprite _loadingPfp;

		private Coroutine? _lastPfpSetter;

		private Coroutine? _lastBannerSetter;

		private Coroutine? _lastUsernameSetter;

		private Friend _user;

		private OnlineScore? _score;

		public void SetValuesAndEnable(MonoBehaviour coroutineRunner, OnlineScore? onlineScore)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			if (onlineScore == null)
			{
				SetNullValues();
				return;
			}
			_score = onlineScore;
			_user = new Friend(SteamId.op_Implicit(onlineScore.SteamId));
			((IText)RankNumber).SetText((onlineScore.Index + 1).ToString());
			IText obj = (IText)Rooms;
			int rooms = onlineScore.Score.Rooms;
			obj.SetText(rooms.ToString());
			((IText)Difficulty).SetText(DdUtils.IntToDifficulty((int)onlineScore.Difficulty));
			if (_lastUsernameSetter != null)
			{
				coroutineRunner.StopCoroutine(_lastUsernameSetter);
			}
			_lastUsernameSetter = coroutineRunner.StartCoroutine(SetUsername(_user));
			if (_lastPfpSetter != null)
			{
				coroutineRunner.StopCoroutine(_lastPfpSetter);
			}
			_lastPfpSetter = coroutineRunner.StartCoroutine(SetAvatar(_user));
			if ((Object)(object)Banner != (Object)null)
			{
				if (_lastBannerSetter != null)
				{
					coroutineRunner.StopCoroutine(_lastBannerSetter);
				}
				_lastBannerSetter = coroutineRunner.StartCoroutine(SetBanner(_user));
			}
			((Component)this).gameObject.SetActive(true);
		}

		public void SetNullValues()
		{
			((IText)RankNumber).SetText("#-");
			((IText)Username).SetText("-");
			((IText)Rooms).SetText("-");
			((IText)Difficulty).SetText("(-)");
			ProfileActual.sprite = _loadingPfp;
			((Component)this).gameObject.SetActive(true);
		}

		private IEnumerator SetUsername(Friend user)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			Task<string> usernameTask = Users.GetUsername(OnlineFunctionality.Context, SteamId.op_Implicit(user.Id));
			yield return (object)new WaitUntil((Func<bool>)(() => usernameTask.IsCompleted));
			string username = usernameTask.Result;
			if (_score.SteamId == SteamId.op_Implicit(SteamClient.SteamId))
			{
				username = "<color=orange>" + username + "</color>";
			}
			((IText)Username).SetText(username);
		}

		private IEnumerator SetAvatar(Friend user)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			ProfileActual.sprite = _loadingPfp;
			Task<Image?> imageTask = ((Friend)(ref user)).GetMediumAvatarAsync();
			yield return (object)new WaitUntil((Func<bool>)(() => imageTask.IsCompleted));
			Texture2D texture2D = new Texture2D((int)imageTask.Result.Value.Width, (int)imageTask.Result.Value.Height, (TextureFormat)4, false);
			texture2D.LoadRawTextureData(imageTask.Result.Value.Data);
			texture2D.Apply();
			ProfileActual.sprite = Sprite.Create(texture2D, new Rect(0f, 0f, (float)((Texture)texture2D).width, (float)((Texture)texture2D).height), Vector2.one / 2f);
		}

		private IEnumerator SetBanner(Friend user)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			((Component)Banner).gameObject.SetActive(false);
			Task<CosmeticLoadout> loadoutTask = Items.GetLoadout(OnlineFunctionality.Context, SteamId.op_Implicit(user.Id));
			Task<Cms> cmsTask = OnlineFunctionality.GetContent();
			yield return (object)new WaitUntil((Func<bool>)(() => cmsTask.IsCompleted && loadoutTask.IsCompleted));
			if (cmsTask.Result.Banners.TryGetValue(loadoutTask.Result.BannerId, out var banner))
			{
				AsyncOperationHandle<Sprite?> bannerLoadTask = Addressables.Instance.LoadAssetAsync<Sprite>((object)banner.Asset.AddressablePath);
				yield return (object)new WaitUntil((Func<bool>)(() => bannerLoadTask.IsDone));
				if (!((Object)(object)bannerLoadTask.Result == (Object)null))
				{
					Banner.sprite = bannerLoadTask.Result;
					((Component)Banner).gameObject.SetActive(true);
				}
			}
		}

		public void OpenProfile()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			Application.OpenURL(string.Format(OnlineFunctionality.LastFetchedContent.GetString("constants.website_users"), _user.Id));
		}
	}
	public class LoadoutHud : MonoBehaviour
	{
		private static readonly Dictionary<StoreItemType, StoreItemType> s_alternateSwapDict = new Dictionary<StoreItemType, StoreItemType>
		{
			{
				(StoreItemType)1,
				(StoreItemType)7
			},
			{
				(StoreItemType)2,
				(StoreItemType)8
			},
			{
				(StoreItemType)3,
				(StoreItemType)9
			},
			{
				(StoreItemType)7,
				(StoreItemType)1
			},
			{
				(StoreItemType)8,
				(StoreItemType)2
			},
			{
				(StoreItemType)9,
				(StoreItemType)3
			}
		};

		[SerializeField]
		private TMP_Text _itemNameText;

		[SerializeField]
		private TMP_Text _categoryTitle;

		[SerializeField]
		private GameObject _page;

		[SerializeField]
		private GameObject _templateItemButton;

		[SerializeField]
		private Transform _itemButtonHolder;

		[SerializeField]
		private GameObject _alternateButton;

		[SerializeField]
		private Button _equipButton;

		[SerializeField]
		private TMP_Text _equipButtonText;

		[SerializeField]
		private LoadoutHudVariantButton[] _variantButtons;

		[SerializeField]
		private GameObject _presentConfigButton;

		private List<GameObject> _currentItemButtons = new List<GameObject>();

		private Item? _selectedItem;

		private StoreItemType _currentItemType;

		public bool HasNoVariations(StoreItemType itemType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)itemType == 0 || (int)itemType == 6)
			{
				return true;
			}
			return false;
		}

		public bool HasAlternates(StoreItemType itemType)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			return s_alternateSwapDict.ContainsKey(itemType);
		}

		private void Awake()
		{
			SelectItemType(1);
		}

		private void OnEnable()
		{
			((MonoBehaviour)this).StartCoroutine(FetchLoadoutBeforeEnable());
		}

		private IEnumerator FetchLoadoutBeforeEnable()
		{
			_page.SetActive(false);
			Task loadoutTask = CosmeticManager.FetchLoadout();
			yield return (object)new WaitUntil((Func<bool>)(() => loadoutTask.IsCompleted));
			_page.SetActive(true);
		}

		private void OnDisable()
		{
			CosmeticManager.UpdateLoadout();
		}

		public void SelectItemType(int itemType)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			_currentItemType = (StoreItemType)itemType;
			((MonoBehaviour)this).StartCoroutine(SetSlotPage());
		}

		public void SwapToAlt()
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: 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_004d: Expected I4, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!HasAlternates(_currentItemType))
			{
				Plugin.Log.LogWarning((object)$"SwapToAlt called with unsupported item {_currentItemType} - shouldn't happen.");
			}
			else
			{
				SelectItemType((int)s_alternateSwapDict[_currentItemType]);
			}
		}

		private IEnumerator SetSlotPage()
		{
			_page.SetActive(false);
			Task<bool> onlineTask = Api.ServerOnline(OnlineFunctionality.Context);
			yield return (object)new WaitUntil((Func<bool>)(() => onlineTask.IsCompleted));
			if (!onlineTask.Result)
			{
				MonoSingleton<HudMessageReceiver>.Instance.SendHudMessage("Server offline!", "", "", 0, false);
				yield break;
			}
			Task<Cms> cmsTask = OnlineFunctionality.GetContent();
			yield return (object)new WaitUntil((Func<bool>)(() => cmsTask.IsCompleted));
			Cms cms = cmsTask.Result;
			_categoryTitle.text = cms.GetString("category." + ((object)(StoreItemType)(ref _currentItemType)).ToString().ToLower());
			List<Item> itemList = new List<Item>();
			Item item3 = default(Item);
			foreach (string itemId in CosmeticManager.AllOwned)
			{
				if (cms.TryGetItem(itemId, ref item3) && item3.Descriptor.Type == _currentItemType)
				{
					itemList.Add(item3);
					item3 = null;
				}
			}
			foreach (GameObject oldItemButton in _currentItemButtons)
			{
				Object.Destroy((Object)(object)oldItemButton);
			}
			IEnumerable<Item> orderedList = itemList.OrderBy((Item x) => CosmeticLoadout.DefaultItems.Contains(x.Descriptor.Id) ? string.Empty : cms.GetString(x.Descriptor.Name));
			foreach (Item item2 in orderedList)
			{
				AddItem(item2);
			}
			string targetId;
			if (HasNoVariations(_currentItemType))
			{
				targetId = GetEquippedItemId(_currentItemType);
			}
			else
			{
				targetId = GetEquippedItemId(_currentItemType, 0);
			}
			if (targetId != null)
			{
				SetItem(orderedList.FirstOrDefault((Func<Item, bool>)((Item item) => item.Descriptor.Id == targetId)));
			}
			else
			{
				SetItem(null);
			}
			_alternateButton.SetActive(HasAlternates(_currentItemType));
			_presentConfigButton.SetActive((int)_currentItemType == 6);
			_page.SetActive(true);
		}

		private void AddItem(Item item)
		{
			GameObject val = Object.Instantiate<GameObject>(_templateItemButton, _itemButtonHolder);
			val.GetComponent<LoadoutHudItemButton>().SetUp(this, item);
			_currentItemButtons.Add(val);
		}

		public void SetItem(Item? item)
		{
			_itemNameText.text = ((item != null) ? OnlineFunctionality.LastFetchedContent.GetString(item.Descriptor.Name) : "-");
			_selectedItem = item;
			UpdateEquipButtons(item);
		}

		private void UpdateEquipButtons(Item? item)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			if (HasNoVariations(_currentItemType))
			{
				EnableSingleEquipButton(item);
			}
			else
			{
				EnableVariationEquipButtons(item);
			}
		}

		private void EnableSingleEquipButton(Item? item)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			LoadoutHudVariantButton[] variantButtons = _variantButtons;
			foreach (LoadoutHudVariantButton loadoutHudVariantButton in variantButtons)
			{
				((Component)loadoutHudVariantButton).gameObject.SetActive(false);
			}
			((Component)_equipButton).gameObject.SetActive(true);
			if (item != null)
			{
				string text = ((GetEquippedItemId(_currentItemType) == item.Descriptor.Id) ? "equipped" : "unequipped");
				_equipButtonText.text = OnlineFunctionality.LastFetchedContent.GetString("shop." + text);
				((Selectable)_equipButton).interactable = true;
			}
			else
			{
				_equipButtonText.text = OnlineFunctionality.LastFetchedContent.GetString("shop.unequipped");
				((Selectable)_equipButton).interactable = false;
			}
		}

		private void EnableVariationEquipButtons(Item? item)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			((Component)_equipButton).gameObject.SetActive(false);
			LoadoutHudVariantButton[] variantButtons = _variantButtons;
			foreach (LoadoutHudVariantButton loadoutHudVariantButton in variantButtons)
			{
				((Component)loadoutHudVariantButton).gameObject.SetActive(true);
				if (item != null)
				{
					loadoutHudVariantButton.SetState(GetEquippedItemId(_currentItemType, loadoutHudVariantButton.VariationIndex) == item.Descriptor.Id);
					loadoutHudVariantButton.SetInteractable(interactable: true);
				}
				else
				{
					loadoutHudVariantButton.SetState(on: false);
					loadoutHudVariantButton.SetInteractable(interactable: false);
				}
			}
		}

		public string? GetEquippedItemId(StoreItemType itemType)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			if ((int)itemType != 0)
			{
				if ((int)itemType == 6)
				{
					return CosmeticManager.Loadout.PresentId;
				}
				Plugin.Log.LogWarning((object)$"Item type {_currentItemType} is not supported for GetEquippedItemId(StoreItemType)");
				return null;
			}
			return CosmeticManager.Loadout.BannerId;
		}

		public string? GetEquippedItemId(StoreItemType itemType, int variation)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			List<string> loadoutSlotList = GetLoadoutSlotList(_currentItemType);
			if (loadoutSlotList == null)
			{
				Plugin.Log.LogWarning((object)$"{_currentItemType} loadoutSlotList was null.");
				return string.Empty;
			}
			if (loadoutSlotList.Count <= variation)
			{
				Plugin.Log.LogWarning((object)$"{variation} out of range of slot {itemType}.");
				return string.Empty;
			}
			return loadoutSlotList[variation];
		}

		public List<string>? GetLoadoutSlotList(StoreItemType itemType)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected I4, but got Unknown
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			switch (itemType - 1)
			{
			case 0:
				return CosmeticManager.Loadout.RevolverIds;
			case 6:
				return CosmeticManager.Loadout.AltRevolverIds;
			case 1:
				return CosmeticManager.Loadout.ShotgunIds;
			case 7:
				return CosmeticManager.Loadout.AltShotgunIds;
			case 2:
				return CosmeticManager.Loadout.NailgunIds;
			case 8:
				return CosmeticManager.Loadout.AltNailgunIds;
			case 3:
				return CosmeticManager.Loadout.RailcannonIds;
			case 4:
				return CosmeticManager.Loadout.RocketIds;
			default:
				Plugin.Log.LogWarning((object)$"Item type {_currentItemType} is not supported for GetLoadoutSlotList");
				return null;
			}
		}

		public void EquipForVariation(int variationIndex)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			List<string> loadoutSlotList = GetLoadoutSlotList(_currentItemType);
			if (loadoutSlotList == null)
			{
				Plugin.Log.LogWarning((object)$"{_currentItemType} loadoutSlotList was null.");
				return;
			}
			while (loadoutSlotList.Count < 3)
			{
				loadoutSlotList.Add(string.Empty);
			}
			loadoutSlotList[variationIndex] = _selectedItem.Descriptor.Id;
			UpdateEquipButtons(_selectedItem);
		}

		public void EquipNoVariation()
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			StoreItemType currentItemType = _currentItemType;
			StoreItemType val = currentItemType;
			if ((int)val != 0)
			{
				if ((int)val != 6)
				{
					Plugin.Log.LogWarning((object)$"Item type {_currentItemType} is not supported for EquipNoVariation");
					return;
				}
				CosmeticManager.Loadout.PresentId = _selectedItem.Descriptor.Id;
			}
			else
			{
				CosmeticManager.Loadout.BannerId = _selectedItem.Descriptor.Id;
			}
			UpdateEquipButtons(_selectedItem);
		}
	}
	public class LoadoutHudItemButton : MonoBehaviour
	{
		[SerializeField]
		private Button _button;

		[SerializeField]
		private Image _iconImage;

		public void SetUp(LoadoutHud loadoutHud, Item item)
		{
			((MonoBehaviour)loadoutHud).StartCoroutine(SetUpCoroutine(loadoutHud, item));
		}

		private IEnumerator SetUpCoroutine(LoadoutHud loadoutHud, Item item)
		{
			LoadoutHud loadoutHud2 = loadoutHud;
			Item item2 = item;
			((Component)this).gameObject.SetActive(false);
			AsyncOperationHandle<Sprite?> iconLoad = Addressables.LoadAssetAsync<Sprite>((object)item2.Descriptor.Icon.AddressablePath);
			yield return (object)new WaitUntil((Func<bool>)(() => iconLoad.IsDone));
			if ((Object)(object)iconLoad.Result == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Couldn't load icon for item " + item2.Descriptor.Id + ". Not showing button"));
			}
			_iconImage.sprite = iconLoad.Result;
			((UnityEvent)_button.onClick).AddListener((UnityAction)delegate
			{
				loadoutHud2.SetItem(item2);
			});
			((Component)this).gameObject.SetActive(true);
		}
	}
	public class LoadoutHudVariantButton : MonoBehaviour
	{
		public int VariationIndex;

		[SerializeField]
		private LoadoutHud _parentHud;

		[SerializeField]
		private ColorBlindGet[] _colourGetters;

		[SerializeField]
		private Button _button;

		[SerializeField]
		private GameObject _check;

		private void OnEnable()
		{
			ColorBlindGet[] colourGetters = _colourGetters;
			foreach (ColorBlindGet val in colourGetters)
			{
				val.variationNumber = VariationIndex;
				val.UpdateColor();
			}
		}

		private void Awake()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			((UnityEvent)_button.onClick).AddListener((UnityAction)delegate
			{
				_parentHud.EquipForVariation(VariationIndex);
			});
		}

		public void SetState(bool on)
		{
			_check.SetActive(on);
		}

		public void SetInteractable(bool interactable)
		{
			((Selectable)_button).interactable = interactable;
		}
	}
	public class MoneyCounter : MonoBehaviour
	{
		[SerializeField]
		private AudioSource _moneyDecreaseTick;

		[SerializeField]
		private float _moneyTickInterval;

		[SerializeField]
		private float _moneyDecreaseInterval;

		[SerializeField]
		private TMP_Text _moneyCounter;

		private Coroutine? _lastMoneyRefresher;

		private int _counterMoney = 0;

		public void SetValue(int amount)
		{
			_counterMoney = amount;
			_moneyCounter.text = amount.ToString();
		}

		public void RefreshMoney(int targetMoney)
		{
			if (_lastMoneyRefresher != null)
			{
				((MonoBehaviour)this).StopCoroutine(_lastMoneyRefresher);
			}
			_lastMoneyRefresher = ((MonoBehaviour)this).StartCoroutine(RefreshMoneyCoroutine(targetMoney));
		}

		private IEnumerator RefreshMoneyCoroutine(int targetMoney)
		{
			float timeSinceTick = 0f;
			float timeSinceDecrease = 0f;
			while (_counterMoney != targetMoney)
			{
				timeSinceTick += Time.deltaTime;
				timeSinceDecrease += Time.deltaTime;
				if (timeSinceTick > _moneyTickInterval)
				{
					_moneyDecreaseTick.Play();
					timeSinceTick = 0f;
				}
				if (timeSinceDecrease > _moneyDecreaseInterval)
				{
					SetValue(--_counterMoney);
				}
				yield return null;
			}
		}
	}
	public class Podium : MonoBehaviour
	{
		[SerializeField]
		private MeshRenderer[] _pfpRenderers;

		[SerializeField]
		private TMP_Text[] _nameTexts;

		private void Awake()
		{
			((MonoBehaviour)this).StartCoroutine(SetValues());
		}

		private IEnumerator SetValues()
		{
			Task<OnlineScore[]> scoresTask = Scores.GetScoreRange(OnlineFunctionality.Context, 0, 3);
			yield return (object)new WaitUntil((Func<bool>)(() => scoresTask.IsCompleted));
			int index = 0;
			OnlineScore[] result = scoresTask.Result;
			foreach (OnlineScore score in result)
			{
				((MonoBehaviour)this).StartCoroutine(SetPfp(score.SteamId, index));
				((MonoBehaviour)this).StartCoroutine(SetUsername(score.SteamId, index));
				index++;
			}
		}

		private IEnumerator SetUsername(ulong steamId, int index)
		{
			Task<string> usernameTask = Users.GetUsername(OnlineFunctionality.Context, steamId);
			yield return (object)new WaitUntil((Func<bool>)(() => usernameTask.IsCompleted));
			_nameTexts[index].text = $"#{index + 1} - " + usernameTask.Result.ToUpperInvariant();
		}

		private IEnumerator SetPfp(ulong steamId, int index)
		{
			Friend val = new Friend(SteamId.op_Implicit(steamId));
			Task<Image?> imageTask = ((Friend)(ref val)).GetLargeAvatarAsync();
			float startTime = Time.time;
			yield return (object)new WaitUntil((Func<bool>)(() => imageTask == null || imageTask.IsCompleted || imageTask.IsFaulted || imageTask.IsCanceled || startTime - Time.time > 10f));
			if (imageTask?.Result.HasValue ?? false)
			{
				Texture2D texture2D = new Texture2D((int)imageTask.Result.Value.Width, (int)imageTask.Result.Value.Height, (TextureFormat)4, false);
				texture2D.LoadRawTextureData(imageTask.Result.Value.Data);
				texture2D.Apply();
				Material[] materialArray = ((Renderer)_pfpRenderers[index]).materials;
				materialArray[1].mainTextureScale = new Vector2(1f, -1f);
				materialArray[1].mainTexture = (Texture)(object)texture2D;
				((Renderer)_pfpRenderers[index]).materials = materialArray;
			}
		}
	}
	public class PresentColourPicker : MonoBehaviour
	{
		[SerializeField]
		private PresentColourUi _parent;

		[SerializeField]
		private int _colourIndex;

		[SerializeField]
		private Slider[] _sliders;

		[SerializeField]
		private Image _image;

		private void Awake()
		{
			for (int i = 0; i < _sliders.Length; i++)
			{
				int currentIndex = i;
				((UnityEvent<float>)(object)_sliders[i].onValueChanged).AddListener((UnityAction<float>)delegate(float value)
				{
					_parent.SliderChanged(_colourIndex, currentIndex, value);
					UpdateSelf();
				});
			}
			UpdateSelf();
		}

		public void UpdateSelf()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			Color colour = ConfigFile.Instance.Data.GetColour(_colourIndex);
			for (int i = 0; i < _sliders.Length; i++)
			{
				_sliders[i].SetValueWithoutNotify(((Color)(ref colour))[i]);
			}
			((Graphic)_image).color = colour;
		}
	}
	public class PresentColourUi : MonoBehaviour
	{
		public static readonly List<SerializableColour> DefaultColours = new List<SerializableColour>(4)
		{
			new SerializableColour(0f, 0.91f, 1f, 1f),
			new SerializableColour(0.27f, 1f, 0.27f, 1f),
			new SerializableColour(1f, 0.24f, 0.24f, 1f),
			new SerializableColour(1f, 0.88f, 0.24f, 1f)
		};

		public void SliderChanged(int colourIndex, int rgbIndex, float value)
		{
			Plugin.Log.LogMessage((object)$"Colour {colourIndex} [{rgbIndex}] = {value}");
			List<SerializableColour> presentColours = ConfigFile.Instance.Data.PresentColours;
			SerializableColour serializableColour = presentColours[colourIndex];
			serializableColour[rgbIndex] = value;
			presentColours[colourIndex] = serializableColour;
		}

		public void ResetColour(int colourIndex)
		{
			ConfigFile.Instance.Data.PresentColours[colourIndex] = DefaultColours[colourIndex];
		}
	}
	[HarmonyPatch]
	public class PresentTimeHud : MonoSingleton<PresentTimeHud>
	{
		public const float DangerTime = 10f;

		public Image[] PresentImages;

		public TMP_Text Timer;

		public TMP_Text CompleteRooms;

		public Color TimerColour;

		public Color TimerDangerColour;

		private float _lastSetSeconds;

		private float _lerpProgress;

		private float _originalFontSize;

		private Vector3 _timerStartPos;

		public void Start()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			_originalFontSize = Timer.fontSize;
			_timerStartPos = Timer.transform.localPosition;
		}

		private void Update()
		{
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			if (!MonoSingleton<GameManager>.Instance.GameStarted)
			{
				return;
			}
			if (MonoSingleton<GameManager>.Instance.TimerActive)
			{
				Timer.text = TimeSpan.FromSeconds(MonoSingleton<GameManager>.Instance.TimeLeft).ToString("mm\\:ss\\.fff", new CultureInfo("en-US"));
				Timer.fontSize = Mathf.MoveTowards(Timer.fontSize, _originalFontSize, 75f * Time.deltaTime);
				_lastSetSeconds = MonoSingleton<GameManager>.Instance.TimeLeft;
				_lerpProgress = 0f;
			}
			else
			{
				if (MonoSingleton<GameManager>.Instance.TimeLeft > 10f)
				{
					MonoSingleton<CameraController>.Instance.StopShake();
				}
				float num = Mathf.Lerp(_lastSetSeconds, MonoSingleton<GameManager>.Instance.TimeLeft, _lerpProgress);
				Timer.text = TimeSpan.FromSeconds(num).Formatted();
				Timer.fontSize = _originalFontSize * (1f + _lerpProgress * 0.15f);
				_lerpProgress += Time.deltaTime / 0.5f;
			}
			if (MonoSingleton<GameManager>.Instance.TimeLeft <= 10f)
			{
				((Graphic)Timer).color = TimerDangerColour;
				Timer.transform.localPosition = _timerStartPos + new Vector3((float)Random.Range(-1, 1), (float)Random.Range(-1, 1), 0f);
				MonoSingleton<CameraController>.Instance.CameraShake((10f - MonoSingleton<GameManager>.Instance.TimeLeft) / 50f);
			}
			else
			{
				((Graphic)Timer).color = TimerColour;
				Timer.transform.localPosition = _timerStartPos;
			}
			if ((Object)(object)MonoSingleton<GameManager>.Instance.CurrentRoom != (Object)null)
			{
				for (int i = 0; i < 4; i++)
				{
					PresentImages[i].fillAmount = FindFill((WeaponVariant)i);
				}
			}
			CompleteRooms.text = MonoSingleton<GameManager>.Instance.RoomsComplete.ToString();
		}

		private float FindFill(WeaponVariant colour)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			float num = MonoSingleton<GameManager>.Instance.CurrentRoom.PresentColourAmounts[colour];
			return 1f - (float)MonoSingleton<GameManager>.Instance.CurrentRoom.AmountDelivered[colour] / num;
		}

		[HarmonyPatch(typeof(HudController), "Start")]
		[HarmonyPostfix]
		private static void AddSelf(HudController __instance)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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)
			if (!__instance.altHud && !MapInfoBase.InstanceAnyType.hideStockHUD)
			{
				GameObject val = Addressables.LoadAssetAsync<GameObject>((object)"Assets/Delivery/Prefabs/HUD/Present Panel.prefab").WaitForCompletion();
				GameObject val2 = Object.Instantiate<GameObject>(val, ((Component)__instance.hudpos).transform);
				val2.transform.localPosition = val.transform.localPosition;
				val2.gameObject.SetActive(false);
			}
		}
	}
	public class ReachValueText : MonoBehaviour
	{
		public enum IntOrFloat
		{
			Int,
			Float
		}

		public IntOrFloat Type;

		public Text Text;

		public float Target;

		public string Format;

		public string StartValue;

		public float ChangePerSecond;

		public bool IsTimestamp;

		private float _timeElapsed;

		private AudioSource _audio;

		private float _currentValue;

		[HideInInspector]
		public bool Done;

		private void OnEnable()
		{
			MonoSingleton<EndScreen>.Instance.CurrentText = this;
			Text.text = StartValue;
			_audio = ((Component)this).GetComponent<AudioSource>();
			AudioSource audio = _audio;
			if (audio != null)
			{
				audio.Play();
			}
		}

		private void Update()
		{
			if (MonoSingleton<EndScreen>.Instance.Skipping)
			{
				_currentValue = Target;
				SetText();
			}
			if (Target == _currentValue)
			{
				SetText();
				Done = true;
				((Behaviour)this).enabled = false;
				AudioSource audio = _audio;
				if (audio != null)
				{
					audio.Stop();
				}
			}
			else
			{
				_timeElapsed += Time.unscaledDeltaTime;
				_currentValue = Mathf.MoveTowards(_currentValue, Target, ChangePerSecond * Time.unscaledDeltaTime);
				SetText();
			}
		}

		private void SetText()
		{
			float num = ((Type == IntOrFloat.Int) ? Mathf.Floor(_currentValue) : _currentValue);
			Text.text = ((!IsTimestamp) ? string.Format(Format, num) : TimeSpan.FromSeconds(num).Formatted());
		}
	}
	public class ShopItemPanel : MonoBehaviour
	{
		[SerializeField]
		private Button _button;

		[SerializeField]
		private TMP_Text _itemName;

		[SerializeField]
		private TMP_Text _itemCost;

		[SerializeField]
		private TMP_Text _itemType;

		[SerializeField]
		private Image _iconImage;

		[SerializeField]
		private Image _moneyIcon;

		private JollyTerminalShop _parentShop;

		private ItemDescriptor _itemDescriptor;

		private string _ownedString;

		public void SetUp(JollyTerminalShop parentShop, ItemDescriptor itemDescriptor)
		{
			((Component)this).gameObject.SetActive(false);
			_itemDescriptor = itemDescriptor;
			_parentShop = parentShop;
			((MonoBehaviour)parentShop).StartCoroutine(SetUpCoroutine());
		}

		private IEnumerator SetUpCoroutine()
		{
			Task<Cms> cmsTask = OnlineFunctionality.GetContent();
			yield return (object)new WaitUntil((Func<bool>)(() => cmsTask.IsCompleted));
			Cms cms = cmsTask.Result;
			_ownedString = cms.GetString("shop.owned");
			_itemName.text = cms.GetString(_itemDescriptor.Name);
			_itemCost.text = _itemDescriptor.ShopPrice.ToString();
			_itemType.text = cms.GetString("category." + ((object)(StoreItemType)(ref _itemDescriptor.Type)).ToString().ToLower());
			if (CosmeticManager.AllOwned.Contains(_itemDescriptor.Id))
			{
				SetOwned();
			}
			AsyncOperationHandle<Sprite> iconCoroutine = Addressables.LoadAssetAsync<Sprite>((object)_itemDescriptor.Icon.AddressablePath);
			yield return (object)new WaitUntil((Func<bool>)(() => iconCoroutine.IsDone));
			_iconImage.sprite = iconCoroutine.Result;
			((Component)this).gameObject.SetActive(true);
		}

		public void Buy()
		{
			_parentShop.BuyItem(_itemDescriptor);
		}

		public void Enable()
		{
			if (CosmeticManager.AllOwned.Contains(_itemDescriptor.Id))
			{
				SetOwned();
			}
			else
			{
				((Selectable)_button).interactable = true;
			}
		}

		public void Disable()
		{
			((Selectable)_button).interactable = false;
		}

		private void SetOwned()
		{
			_itemCost.text = _ownedString;
			Disable();
			((Component)_moneyIcon).gameObject.SetActive(false);
		}
	}
	[HarmonyPatch]
	public class TabMenu : MonoBehaviour
	{
		private static GameObject? s_menuObject;

		[SerializeField]
		private TMP_Text _map;

		[SerializeField]
		private TMP_Text _time;

		[SerializeField]
		private TMP_Text _kills;

		private int _roomEnemyCount;

		private int _killsOnEnter;

		private void Awake()
		{
			MonoSingleton<GameManager>.Instance.RoomStarted += delegate(Room room)
			{
				if (!((Object)(object)room.Arena == (Object)null) && !((Object)(object)MonoSingleton<StatsManager>.Instance == (Object)null))
				{
					_roomEnemyCount = room.Arena.enemies.Length;
					_killsOnEnter = MonoSingleton<StatsManager>.Instance.kills;
				}
			};
		}

		private void Update()
		{
			if (!((Object)(object)MonoSingleton<GameManager>.Instance == (Object)null) && !((Object)(object)MonoSingleton<GameManager>.Instance.CurrentRoomData == (Object)null))
			{
				_map.text = MonoSingleton<GameManager>.Instance.CurrentRoomData.Name;
				_time.text = TimeSpan.FromSeconds(MonoSingleton<GameManager>.Instance.TimeElapsed).ToString("mm':'ss'.'ff");
				_kills.text = (_roomEnemyCount - (MonoSingleton<StatsManager>.Instance.kills - _killsOnEnter)).ToString();
			}
		}

		[HarmonyPatch(typeof(LevelStatsEnabler), "Start")]
		[HarmonyPostfix]
		private static void AddSelf(LevelStatsEnabler __instance)
		{
			//IL_001c: 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 (AssetManager.InSceneFromThisMod)
			{
				if (s_menuObject == null)
				{
					s_menuObject = Addressables.LoadAssetAsync<GameObject>((object)"Assets/Delivery/Prefabs/HUD/Game Stats.prefab").WaitForCompletion();
				}
				((Component)__instance).gameObject.SetActive(true);
				__instance.levelStats = Object.Instantiate<GameObject>(s_menuObject, ((Component)__instance).transform);
				__instance.levelStats.SetActive(false);
			}
		}
	}
	public interface IText
	{
		void SetText(string text);
	}
	public class TmpText : MonoBehaviour, IText
	{
		private TMP_Text _text;

		public void SetText(string text)
		{
			if ((Object)(object)_text == (Object)null)
			{
				_text = ((Component)this).GetComponent<TMP_Text>();
			}
			_text.text = text;
		}
	}
	public class UnityText : MonoBehaviour, IText
	{
		private Text _text;

		public void SetText(string text)
		{
			if ((Object)(object)_text == (Object)null)
			{
				_text = ((Component)this).GetComponent<Text>();
			}
			_text.text = text;
		}
	}
	public class UpdateScreen : MonoBehaviour
	{
		private void Awake()
		{
			((Component)this).gameObject.SetActive(false);
			((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(EnableIfNeeded());
		}

		private void Update()
		{
			((Behaviour)MonoSingleton<NewMovement>.Instance).enabled = false;
			((Behaviour)MonoSingleton<GunControl>.Instance).enabled = false;
			((Behaviour)MonoSingleton<FistControl>.Instance).enabled = false;
			Time.timeScale = 0f;
		}

		private IEnumerator EnableIfNeeded()
		{
			Task<bool> onlineTask = Api.ServerOnline(OnlineFunctionality.Context);
			yield return (object)new WaitUntil((Func<bool>)(() => onlineTask.IsCompleted));
			if (onlineTask.Result)
			{
				Task<bool> updateRequiredTask = Api.UpdateRequired(OnlineFunctionality.Context);
				yield return (object)new WaitUntil((Func<bool>)(() => updateRequiredTask.IsCompleted));
				if (updateRequiredTask.Result)
				{
					((Component)this).gameObject.SetActive(true);
					GameStateManager.Instance.RegisterState(new GameState("pause_updscreen", (GameObject[])(object)new GameObject[1] { ((Component)this).gameObject })
					{
						cursorLock = (LockMode)2,
						cameraInputLock = (LockMode)1,
						playerInputLock = (LockMode)1
					});
					((Behaviour)MonoSingleton<NewMovement>.Instance).enabled = false;
					((Behaviour)MonoSingleton<GunControl>.Instance).enabled = false;
					((Behaviour)MonoSingleton<FistControl>.Instance).enabled = false;
					Time.timeScale = 0f;
				}
			}
		}

		public void ReenablePlayer()
		{
			((Behaviour)MonoSingleton<NewMovement>.Instance).enabled = true;
			((Behaviour)MonoSingleton<GunControl>.Instance).enabled = true;
			((Behaviour)MonoSingleton<FistControl>.Instance).enabled = true;
			MonoSingleton<TimeController>.Instance.RestoreTime();
		}

		public void OpenThunderstore()
		{
			Application.OpenURL("https://thunderstore.io/c/ultrakill/p/Waff1e/Divine_Delivery/");
		}
	}
}
namespace EndlessDelivery.ScoreManagement
{
	public class ScoreManager
	{
		public static SaveFile<Dictionary<int, Score>> LocalHighscores = SaveFile.RegisterFile<Dictionary<int, Score>>(new SaveFile<Dictionary<int, Score>>("local_scores.json", "Divine Delivery", new Dictionary<int, Score>()));

		public static Score CurrentDifficultyHighscore
		{
			get
			{
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				Score value;
				return (Score)(LocalHighscores.Data.TryGetValue(MonoSingleton<PrefsManager>.Instance.GetInt("difficulty", 0), out value) ? ((object)value) : ((object)new Score(0, 0, 0, 0f, 0)));
			}
		}

		public static bool CanSubmit()
		{
			List<string> reasons;
			return CanSubmit(out reasons);
		}

		public static bool CanSubmit(out List<string> reasons)
		{
			return !EndlessDelivery.Anticheat.Anticheat.HasIllegalMods(out reasons) && !MonoSingleton<CheatsController>.Instance.cheatsEnabled;
		}

		public static bool CanSubmitOnline()
		{
			List<string> reasons;
			return CanSubmit(out reasons) && MonoSingleton<PrefsManager>.Instance.GetInt("difficulty", 0) >= 3;
		}

		public static async Task<OnlineScore?> SubmitScore(Score score, short difficulty)
		{
			if (!CanSubmitOnline())
			{
				return null;
			}
			if (await Api.UpdateRequired(OnlineFunctionality.Context))
			{
				return null;
			}
			if (score > CurrentDifficultyHighscore)
			{
				LocalHighscores.Data[difficulty] = score;
			}
			try
			{
				OnlineScore submittedScore = await Scores.SubmitScore(OnlineFunctionality.Context, new SubmitScoreData(score, difficulty));
				AchievementManager.CheckOnline(submittedScore, await Users.GetBestScore(OnlineFunctionality.Context, SteamId.op_Implicit(SteamClient.SteamId)), await Users.GetLifetimeStats(OnlineFunctionality.Context, SteamId.op_Implicit(SteamClient.SteamId)));
				return submittedScore;
			}
			catch (Exception ex)
			{
				MonoSingleton<HudMessageReceiver>.Instance.SendHudMessage($"Score submit error!\nUpdate or upload your logs. {ex.GetType()}.", "", "", 0, false);
				Plugin.Log.LogError((object)ex.ToString());
				return null;
			}
		}
	}
}
namespace EndlessDelivery.Online
{
	[HarmonyPatch]
	public static class DiscordRpc
	{
		[HarmonyPatch(typeof(DiscordController), "SendActivity")]
		[HarmonyPrefix]
		private static void UpdateActivity(DiscordController __instance)
		{
			if (AssetManager.InSceneFromThisMod)
			{
				SetActivity(ref __instance.cachedActivity);
			}
		}

		private static void SetActivity(ref Activity activity)
		{
			activity.Assets.LargeImage = GetUrl(MonoSingleton<GameManager>.Instance.CurrentRoomData);
			activity.Assets.LargeText = "DIVINE DELIVERY";
			activity.Details = $"ROOMS: {MonoSingleton<GameManager>.Instance.RoomsComplete}";
		}

		private static string GetUrl(RoomData? data)
		{
			return "https://delivery.wafflethings.dev/Resources/DiscordIcons/" + (data?.Id ?? "startroom") + ".png";
		}
	}
	public static class OnlineFunctionality
	{
		public static readonly ApiContext Context = new ApiContext(new HttpClient(), (Func<string>)GetTicket, (Uri)null);

		private static SaveFile<Cms?> s_cmsData = SaveFile.RegisterFile<Cms>(new SaveFile<Cms>("content.json", "Divine Delivery", (Cms)null));

		public static bool LoggedIn { get; private set; }

		public static Cms? LastFetchedContent => s_cmsData.Data;

		public static void Init()
		{
			Plugin.Log.LogMessage((object)"Init called!");
			((MonoBehaviour)CoroutineRunner.Instance).StartCoroutine(InitWhenSteamReady());
		}

		private static IEnumerator InitWhenSteamReady()
		{
			while (!SteamClient.IsValid)
			{
				yield return null;
			}
			Context.Client.DefaultRequestHeaders.Add("DdVersion", "2.2.2");
			Context.Client.DefaultRequestHeaders.Add("DdMods", string.Join(",", Chainloader.PluginInfos.Values.Select((PluginInfo x) => x.Metadata.GUID.Replace(",", string.Empty))));
			Task loginTask = Task.Run((Func<Task?>)Context.Login);
			yield return (object)new WaitUntil((Func<bool>)(() => loginTask.IsCompleted));
			LoggedIn = true;
			Task.Run((Func<Task<Cms>?>)GetContent);
			Task.Run((Func<Task?>)CosmeticManager.FetchLoadout);
		}

		public static string GetTicket()
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			AuthTicket authSessionTicket = SteamUser.GetAuthSessionTicket(default(NetIdentity));
			return BitConverter.ToString(authSessionTicket.Data, 0, authSessionTicket.Data.Length).Replace("-", string.Empty);
		}

		public static async Task<Cms> GetContent()
		{
			ApiContext context = Context;
			Cms data = s_cmsData.Data;
			if (await Content.ContentUpdateRequired(context, ((data != null) ? data.Hash : null) ?? string.Empty))
			{
				Cms downloaded = await Content.DownloadCms(Context);
				if (downloaded == null)
				{
					throw new Exception("CMS download failed!");
				}
				s_cmsData.Data = downloaded;
			}
			return s_cmsData.Data ?? throw new Exception("Couldn't get content and no old content cached.");
		}
	}
}
namespace EndlessDelivery.Gameplay
{
	[HarmonyPatch]
	public class GameManager : MonoSingleton<GameManager>
	{
		public delegate void RoomEvent(Room room);

		public delegate void EnemyEvent(EnemyIdentifier enemy);

		private static SpecialWave[] s_specialWaves = new SpecialWave[3]
		{
			new Radiant(),
			new FireworkWave(),
			new WardWave()
		};

		public const float StartTime = 45f;

		public const float TimeAddLength = 0.5f;

		public const float MaxTime = 90f;

		public const int SpecialWaveStart = 20;

		public const int SpecialWaveInterval = 5;

		public AudioSource TimeAddSound;

		public RoomPool RoomPool;

		[SerializeField]
		private Vector3 _baseRoomPosition = new Vector3(0f, 0f, 100f);

		private Coroutine _pauseCoroutine;

		private List<RoomData> _remainingRooms = new List<RoomData>();

		private List<SpecialWave> _remainingSpecialWaves = new List<SpecialWave>();

		private const int StartingPoints = 10;

		private const int MaxPointGain = 15;

		public bool GameStarted { get; private set; }

		public float TimeLeft { get; private set; }

		public float TimeElapsed { get; private set; }

		public int DeliveredPresents { get; set; }

		public int RoomsComplete { get; private set; }

		public Room CurrentRoom { get; private set; }

		public RoomData CurrentRoomData { get; private set; }

		public Room PreviousRoom { get; private set; }

		public bool TimerActive { get; private set; }

		public int PointsPerWave { get; private set; }

		public Score CurrentScore => new Score(RoomsComplete, MonoSingleton<StatsManager>.Instance.kills, DeliveredPresents, TimeElapsed, ((SaveFile<StartTimes>)(object)StartTimes.Instance).Data.CurrentTimes.SelectedWave);

		public event RoomEvent? RoomStarted;

		public event RoomEvent? RoomCleared;

		public event RoomEvent? RoomComplete;

		public event EnemyEvent? EnemySpawned;

		public static int GetRoomPoints(int roomNumber)
		{
			int num = 10;
			for (int i = 0; i < roomNumber; i++)
			{
				num += Mathf.Min(3 + (i + 1) / 3, 15);
			}
			return num;
		}

		private void Awake()
		{
			EnemyHack.AddToPools(EnemyGroup.Groups[DeliveryEnemyClass.Projectile], EnemyGroup.Groups[DeliveryEnemyClass.Uncommon], EnemyGroup.Groups[DeliveryEnemyClass.Special], EnemyGroup.Groups[DeliveryEnemyClass.Melee]);
		}

		private void SetRoomPool()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			DatedRoomPool currentRoomPool = OnlineFunctionality.LastFetchedContent.CurrentRoomPool;
			if (currentRoomPool == null)
			{
				Plugin.Log.LogWarning((object)"Pool was null, using fallback");
				return;
			}
			string assetPath = OnlineFunctionality.LastFetchedContent.CurrentRoomPool.AssetPath;
			RoomPool roomPool = Addressables.LoadAssetAsync<RoomPool>((object)assetPath).WaitForCompletion();
			if ((Object)(object)roomPool == (Object)null)
			{
				Plugin.Log.LogWarning((object)("Loaded pool at " + assetPath + " was null, using fallback"));
			}
			else
			{
				RoomPool = roomPool;
			}
		}

		private void Update()
		{
			if (GameStarted && MonoSingleton<GunControl>.Instance.activated)
			{
				TimeLeft = Mathf.MoveTowards(TimeLeft, 0f, Time.deltaTime);
				TimeElapsed += Time.deltaTime;
				if (TimeLeft == 0f)
				{
					EndGame();
				}
				if (!CurrentRoom.RoomCleared && CurrentRoom.RoomActivated && CurrentRoom.AllEnemiesSpawned && MonoSingleton<EnemyTracker>.Instance.enemies.All((EnemyIdentifier enemy) => enemy.dead))
				{
					CurrentRoom.RoomCleared = true;
					MonoSingleton<MusicManager>.Instance.PlayCleanMusic();
					this.RoomCleared?.Invoke(CurrentRoom);
					AddTime(6f, "<color=orange>FULL CLEAR</color>");
				}
			}
		}

		public void RegisterEnemySpawned(EnemyIdentifier enemy)
		{
			CurrentRoom.Enemies.Add(enemy);
			this.EnemySpawned?.Invoke(enemy);
		}

		public SpecialWave PickSpecialWave()
		{
			if (_remainingSpecialWaves.Count == 0)
			{
				_remainingSpecialWaves.AddRange(s_specialWaves);
			}
			return _remainingSpecialWaves.Pick();
		}

		public void AddTime(float seconds, string reason)
		{
			if (TimeLeft + seconds > 90f)
			{
				seconds = Mathf.Round(90f - TimeLeft);
			}
			AudioSource timeAddSound = TimeAddSound;
			if (timeAddSound != null)
			{
				timeAddSound.Play();
			}
			TimerActive = false;
			if (_pauseCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_pauseCoroutine);
			}
			_pauseCoroutine = ((MonoBehaviour)this).StartCoroutine(UnpauseTimer());
			MonoSingleton<StyleHUD>.Instance.AddPoints(5, $"{reason} <size=20>({seconds}s)</size>", (GameObject)null, (EnemyIdentifier)null, -1, "", "");
			TimeLeft += seconds;
		}

		public void SilentAddTime(float seconds)
		{
			TimeLeft += seconds;
		}

		private IEnumerator UnpauseTimer()
		{
			yield return (object)new WaitForSeconds(0.5f);
			TimerActive = true;
		}

		private Room GenerateNewRoom()
		{
			//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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			CurrentRoomData = GetRandomRoom();
			return Object.Instantiate<GameObject>(CurrentRoomData.Prefab, _baseRoomPosition + Vector3.right * (float)(RoomsComplete % 3) * 200f, Quaternion.identity).GetComponent<Room>();
		}

		private RoomData GetRandomRoom()
		{
			if (_remainingRooms.Count == 0)
			{
				_remainingRooms.AddRange(RoomPool.Rooms);
			}
			RoomData roomData = _remainingRooms.Pick();
			_remainingRooms.Remove(roomData);
			return roomData;
		}

		public void RoomEnd()
		{
			this.RoomComplete?.Invoke(CurrentRoom);
			RoomsComplete++;
			if (CurrentRoom.RoomHasGameplay)
			{
				AddTime(8f, "<color=orange>ROOM CLEAR</color>");
				PointsPerWave += Mathf.Min(3 + RoomsComplete / 3, 10);
				((SaveFile<StartTimes>)(object)StartTimes.Instance).Data.UpdateAllLowerDifficulty(RoomsComplete, TimeLeft);
				MonoSingleton<NewMovement>.Instance.ResetHardDamage();
				MonoSingleton<NewMovement>.Instance.GetHealth(100, true, false);
				MonoSingleton<NewMovement>.Instance.FullStamina();
			}
			else if (!GameStarted)
			{
				StartGame();
			}
			SetRoom(GenerateNewRoom());
		}

		public void SetRoom(Room room)
		{
			if ((Object)(object)CurrentRoom != (Object)(object)room)
			{
				PreviousRoom = CurrentRoom;
				CurrentRoom = room;
				room.Initialize();
			}
			if (room.RoomHasGameplay && !room.RoomAlreadyVisited)
			{
				room.RoomAlreadyVisited = true;
			}
			this.RoomStarted?.Invoke(CurrentRoom);
		}

		public void StartGame()
		{
			if (!GameStarted)
			{
				SetRoomPool();
				((Component)MonoSingleton<PresentTimeHud>.Instance).gameObject.SetActive(true);
				((Component)((Component)MonoSingleton<StatsManager>.Instance).GetComponentInChildren<MusicManager>(true)).gameObject.SetActive(true);
				MonoSingleton<MusicManager>.Instance.StartMusic();
				RoomsComplete = ((SaveFile<StartTimes>)(object)StartTimes.Instance).Data.CurrentTimes.SelectedWave;
				PointsPerWave = GetRoomPoints(RoomsComplete);
				TimeLeft = ((SaveFile<StartTimes>)(object)StartTimes.Instance).Data.CurrentTimes.GetRoomTime(RoomsComplete);
				TimerActive = true;
				GameStarted = true;
			}
		}

		public void EndGame()
		{
			if (!GameStarted)
			{
				return;
			}
			if (!MonoSingleton<NewMovement>.Instance.dead)
			{
				MonoSingleton<NewMovement>.Instance.GetHurt(1000, false, 1f, false, false, 0.35f, false);
			}
			((Component)MonoSingleton<NewMovement>.Instance.blackScreen).gameObject.SetActive(false);
			MonoSingleton<NewMovement>.Instance.hp = 100;
			GameStarted = false;
			int @int = MonoSingleton<PrefsManager>.Instance.GetInt("difficulty", 0);
			if (ScoreManager.CanSubmit(out List<string> reasons))
			{
				if (!ScoreManager.LocalHighscores.Data.ContainsKey(@int) || CurrentScore > ScoreManager.LocalHighscores.Data[@int])
				{
					MonoSingleton<EndScreen>.Instance.PreviousHighscore = ScoreManager.CurrentDifficultyHighscore;
					MonoSingleton<EndScreen>.Instance.NewBest = true;
				}
				((MonoBehaviour)this).StartCoroutine(ShowAfterSubmit(@int));
			}
			else
			{
				MonoSingleton<HudMessageReceiver>.Instance.SendHudMessage("Score not submitting due to other mods, or cheats enabled. " + string.Join(", ", reasons), "", "", 0, false);
				MonoSingleton<EndScreen>.Instance.Appear();
			}
		}

		private IEnumerator ShowAfterSubmit(int difficulty)
		{
			Task<bool> onlineTask = Api.ServerOnline(OnlineFunctionality.Context);
			yield return (object)new WaitUntil((Func<bool>)(() => onlineTask.IsCompleted));
			if (onlineTask.Result)
			{
				Task<bool> updateRequiredTask = Api.UpdateRequired(OnlineFunctionality.Context);
				yield return (object)new WaitUntil((Func<bool>)(() => updateRequiredTask.IsCompleted));
				if (!updateRequiredTask.Result)
				{
					Task submitTask = ScoreManager.SubmitScore(CurrentScore, (short)difficulty);
					yield return (object)new WaitUntil((Func<bool>)(() => submitTask.IsCompleted));
				}
				else
				{
					MonoSingleton<HudMessageReceiver>.Instance.SendHudMessage("Update required to submit scores!", "", "", 0, false);
				}
			}
			else
			{
				MonoSingleton<HudMessageReceiver>.Instance.SendHudMessage("Server offline!", "", "", 0, false);
			}
			MonoSingleton<EndScreen>.Instance.Appear();
		}

		[HarmonyPatch(typeof(SeasonalHats), "Start")]
		[HarmonyPrefix]
		private static void EnableHats(SeasonalHats __instance)
		{
			if (AssetManager.InSceneFromThisMod)
			{
				__instance.easter.SetActive(false);
				__instance.halloween.SetActive(false);
				__instance.christmas.SetActive(true);
			}
		}

		[HarmonyPatch(typeof(NewMovement), "GetHurt")]
		[HarmonyPostfix]
		private static void CustomDeath(NewMovement __instance)
		{
			if (__instance.dead && AssetManager.InSceneFromThisMod)
			{
				MonoSingleton<GameManager>.Instance.EndGame();
			}
		}
	}
	public static class GenerationEquations
	{
		public static int PresentAmount(int wave)
		{
			int num = Mathf.CeilToInt(Mathf.Log((float)wave, 6.5f) * 3f);
			num = Mathf.Clamp(num, 4, 10);
			Plugin.Log.LogInfo((object)$"{wave} presents: {num}");
			return num;
		}

		public static int[] DistributeBetween(int amount, int number)
		{
			int[] array = new int[amount];
			int num = 0;
			while (number >= 1)
			{
				array[num]++;
				number--;
				num++;
				if (num > amount - 1)
				{
					num = 0;
				}
			}
			return array;
		}
	}
	public class PlayerChimneyFixer : MonoSingleton<PlayerChimneyFixer>
	{
		private bool _isInChimney;

		private Chimney _currentChimney;

		public void EnterChimney(Chimney chimney)
		{
			_isInChimney = true;
			_currentChimney = chimney;
		}

		public void Exit()
		{
			_isInChimney = false;
		}

		private void Update()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type