Decompiled source of Arena Combat v0.1.13

BepInEx/plugins/ArenaCombat/ArenaCombat.dll

Decompiled an hour ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using ArenaCombat.Core;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Splatform;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ArenaCombat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.13.0")]
[assembly: AssemblyInformationalVersion("0.1.13")]
[assembly: AssemblyProduct("ArenaCombat")]
[assembly: AssemblyTitle("ArenaCombat")]
[assembly: AssemblyVersion("0.1.13.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 ArenaCombat
{
	internal sealed class ArenaMenu
	{
		private readonly Plugin plugin;

		private GameObject? panel;

		private GameObject? content;

		private GameObject? selectedFallback;

		private ScrollRect? enemyScroll;

		private Image? reserveFill;

		private Image? selectedIcon;

		private Text? selectedBiome;

		private Text? enemyCount;

		private readonly Dictionary<GameObject, string> rowPrefabs = new Dictionary<GameObject, string>();

		private readonly Dictionary<string, Sprite?> icons = new Dictionary<string, Sprite>(StringComparer.Ordinal);

		private static readonly Color Gold = new Color(0.92f, 0.69f, 0.32f);

		private static readonly string[] FrameEdges = new string[4] { "Top", "Bottom", "Left", "Right" };

		private static readonly Color RowNormal = new Color(0.21f, 0.245f, 0.28f);

		private static readonly Color RowSelected = new Color(0.38f, 0.29f, 0.14f);

		private static readonly Color Muted = new Color(0.8f, 0.82f, 0.82f);

		private const float CardCenterY = -51.5f;

		private const float CardHeight = 527f;

		private const float ListViewportHeight = 426f;

		private const float ListX = -220f;

		private const float EncounterX = 220f;

		private static readonly Color RowBorder = new Color(0.46f, 0.52f, 0.55f, 0.38f);

		private Text? balanceText;

		private Text? selectedText;

		private Text? quoteText;

		private Text? detailText;

		private Text? strengthText;

		private Button? weakerButton;

		private Button? strongerButton;

		private int strengthTenths = 10;

		private Button? summonButton;

		private Button? practiceButton;

		private Button? rewardsButton;

		private readonly List<Button> starButtons = new List<Button>();

		private readonly List<GameObject> rows = new List<GameObject>();

		private InputField? search;

		private Dropdown? biome;

		private MenuSnapshot? snapshot;

		private ZDOID target = ZDOID.None;

		private ZRoutedRpc? world;

		private int serial;

		private int lastApplied;

		private int stars;

		private int commandSerial;

		private bool loot;

		private bool commandPending;

		private string selected = "";

		private string listSignature = "";

		private float nextPoll;

		private float nextSettings;

		private MenuSnapshot? settings;

		private float commandStarted;

		internal bool HasServerSettings => settings != null;

		internal bool BuilderIsAdmin
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer())
				{
					return settings?.BuilderIsAdmin ?? false;
				}
				return true;
			}
		}

		internal bool AdminBuildOnly
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer())
				{
					return settings?.AdminBuildOnly ?? plugin.Settings.AdminBuildOnly.Value;
				}
				return plugin.Settings.AdminBuildOnly.Value;
			}
		}

		internal bool Invulnerable
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer())
				{
					return settings?.Invulnerable ?? plugin.Settings.Invulnerable.Value;
				}
				return plugin.Settings.Invulnerable.Value;
			}
		}

		internal int Maximum
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer())
				{
					return settings?.Maximum ?? plugin.Settings.MaximumActivators.Value;
				}
				return plugin.Settings.MaximumActivators.Value;
			}
		}

		internal int ActivatorCount => settings?.Count ?? 0;

		private static Vector2 Center => new Vector2(0.5f, 0.5f);

		internal void RefreshBuildPermissions()
		{
			nextSettings = 0f;
		}

		internal ArenaMenu(Plugin plugin)
		{
			//IL_003a: 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)
			this.plugin = plugin;
		}

		internal void Update()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			if (GUIManager.IsHeadless())
			{
				return;
			}
			if (world != ZRoutedRpc.instance)
			{
				world = ZRoutedRpc.instance;
				settings = null;
				nextSettings = 0f;
				Close();
			}
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || world == null)
			{
				return;
			}
			if (Time.unscaledTime >= nextSettings)
			{
				nextSettings = Time.unscaledTime + 5f;
				Send(2, ZDOID.None);
			}
			if (!Object.op_Implicit((Object)(object)panel))
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			ZDOMan instance = ZDOMan.instance;
			ZDO val = ((instance != null) ? instance.GetZDO(target) : null);
			float num = settings?.InteractionDistance ?? plugin.Settings.InteractDistance.Value;
			if (!Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting() || val == null || Vector3.Distance(((Component)localPlayer).transform.position, val.GetPosition()) > num + 1f)
			{
				Close();
				return;
			}
			if (Input.GetKeyDown((KeyCode)27))
			{
				Close();
				return;
			}
			if (Time.unscaledTime >= nextPoll)
			{
				nextPoll = Time.unscaledTime + 1f;
				Send(0, target);
			}
			if (commandPending && Time.unscaledTime - commandStarted > 5f)
			{
				commandPending = false;
				Feedback("Request timed out. Refreshing the encounter status.");
				RefreshDetails();
			}
		}

		internal void Open(ZDOID piece)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_0390: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0423: Unknown result type (might be due to invalid IL or missing references)
			//IL_0506: Unknown result type (might be due to invalid IL or missing references)
			//IL_0531: Unknown result type (might be due to invalid IL or missing references)
			//IL_061d: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0706: Unknown result type (might be due to invalid IL or missing references)
			//IL_07d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_080f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0882: Unknown result type (might be due to invalid IL or missing references)
			//IL_08f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_08fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_090f: Unknown result type (might be due to invalid IL or missing references)
			//IL_091d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0938: Unknown result type (might be due to invalid IL or missing references)
			//IL_0953: Unknown result type (might be due to invalid IL or missing references)
			//IL_0973: Unknown result type (might be due to invalid IL or missing references)
			//IL_0983: Unknown result type (might be due to invalid IL or missing references)
			//IL_09aa: Unknown result type (might be due to invalid IL or missing references)
			Close();
			if (GUIManager.IsHeadless() || !Object.op_Implicit((Object)(object)GUIManager.CustomGUIFront))
			{
				return;
			}
			target = piece;
			snapshot = null;
			listSignature = "";
			lastApplied = 0;
			commandPending = false;
			GUIManager instance = GUIManager.Instance;
			panel = instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 900f, 680f, false);
			((Object)panel).name = "ArenaCombatMenu";
			Label("ARENA COORDINATOR", 0f, 296f, 610f, 44f, 32);
			Divider(panel.transform, "Header divider", 0f, 270f, 820f, ornament: true);
			MakeButton("Close", 370f, 296f, 95f, 38f, Close);
			balanceText = Label("Connecting to the arena…", 0f, 246f, 820f, 26f, 18);
			Image val = Surface(panel.transform, "Reserve track", 0f, 224f, 810f, 5f, new Color(0.06f, 0.06f, 0.06f, 0.9f));
			reserveFill = Surface(((Component)val).transform, "Reserve fill", 0f, 0f, 0f, 5f, Gold);
			RectTransform rectTransform = ((Graphic)reserveFill).rectTransform;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0f, 0.5f);
			rectTransform.anchorMax = val2;
			rectTransform.anchorMin = val2;
			rectTransform.pivot = new Vector2(0f, 0.5f);
			CreateScrollArea();
			search = instance.CreateInputField(panel.transform, Center, Center, new Vector2(-322.5f, 150f), (ContentType)0, "Search enemies…", 16, 205f, 36f).GetComponent<InputField>();
			((UnityEvent<string>)(object)search.onValueChanged).AddListener((UnityAction<string>)delegate
			{
				RebuildList();
			});
			biome = instance.CreateDropDown(panel.transform, Center, Center, new Vector2(-112.5f, 150f), 15, 195f, 36f).GetComponent<Dropdown>();
			biome.AddOptions(new List<string> { "All unlocked biomes" });
			((UnityEvent<int>)(object)biome.onValueChanged).AddListener((UnityAction<int>)delegate
			{
				RebuildList();
			});
			biome.captionText.font = instance.AveriaSerif;
			Surface(panel.transform, "Encounter border", 220f, -51.5f, 410f, 527f, new Color(0.64f, 0.48f, 0.26f, 0.75f));
			Surface(panel.transform, "Encounter inset", 220f, -51.5f, 406f, 523f, new Color(0.075f, 0.08f, 0.09f));
			Surface(panel.transform, "Encounter heading", 220f, 155f, 406f, 110f, new Color(0.13f, 0.15f, 0.17f));
			Divider(panel.transform, "Portrait divider", 220f, 100f, 370f, ornament: false);
			Surface(panel.transform, "Portrait backing", 87f, 155f, 64f, 64f, new Color(0.05f, 0.055f, 0.06f));
			selectedIcon = Surface(panel.transform, "Enemy portrait", 87f, 155f, 60f, 60f, Color.white);
			selectedIcon.preserveAspect = true;
			selectedFallback = Silhouette(panel.transform, 87f, 155f, 50f);
			selectedText = Label("Select an enemy", 268f, 168f, 255f, 52f, 24);
			selectedText.alignment = (TextAnchor)3;
			selectedText.resizeTextForBestFit = true;
			selectedText.resizeTextMinSize = 18;
			selectedText.resizeTextMaxSize = 24;
			selectedBiome = Label("", 268f, 130f, 255f, 24f, 16);
			selectedBiome.font = instance.AveriaSerif;
			selectedBiome.alignment = (TextAnchor)3;
			((Graphic)selectedBiome).color = Muted;
			((Graphic)Label("ENEMY LEVEL", 220f, 77f, 370f, 20f, 14)).color = Gold;
			starButtons.Clear();
			for (int num = 0; num <= 2; num++)
			{
				int level = num;
				Button val3 = MakeButton(num + ((num == 1) ? " star" : " stars"), 96 + num * 124, 46f, 116f, 38f, delegate
				{
					stars = level;
					RefreshDetails();
				});
				AddButtonHighlight(val3, "Choice highlight");
				starButtons.Add(val3);
			}
			Divider(panel.transform, "Level divider", 220f, 14f, 370f, ornament: false);
			((Graphic)Label("STRENGTH - HEALTH & DAMAGE", 220f, -7f, 370f, 20f, 13)).color = Gold;
			weakerButton = MakeButton("-", 70f, -36f, 50f, 32f, delegate
			{
				ChangeStrength(-1);
			});
			strongerButton = MakeButton("+", 370f, -36f, 50f, 32f, delegate
			{
				ChangeStrength(1);
			});
			strengthText = Label("1.0x", 220f, -36f, 220f, 32f, 22);
			((Graphic)strengthText).color = Gold;
			Divider(panel.transform, "Strength divider", 220f, -63f, 370f, ornament: false);
			((Graphic)Label("FIGHT MODE", 220f, -84f, 370f, 20f, 13)).color = Gold;
			practiceButton = MakeButton("Practice", 124f, -113f, 178f, 34f, delegate
			{
				loot = false;
				RefreshDetails();
			});
			rewardsButton = MakeButton("Loot rewards", 316f, -113f, 178f, 34f, delegate
			{
				loot = true;
				RefreshDetails();
			});
			AddButtonHighlight(practiceButton, "Choice highlight");
			AddButtonHighlight(rewardsButton, "Choice highlight");
			Divider(panel.transform, "Loot divider", 220f, -141f, 370f, ornament: false);
			((Graphic)Label("RESERVE COST", 220f, -160f, 370f, 20f, 13)).color = Muted;
			quoteText = Label("", 220f, -188f, 370f, 32f, 25);
			((Graphic)quoteText).color = Gold;
			detailText = Label("", 220f, -228f, 370f, 52f, 14);
			detailText.font = instance.AveriaSerif;
			detailText.resizeTextForBestFit = true;
			detailText.resizeTextMinSize = 13;
			detailText.resizeTextMaxSize = 14;
			((Graphic)detailText).color = GUIManager.Instance.ValheimBeige;
			Divider(panel.transform, "Summon divider", 220f, -259f, 370f, ornament: false);
			summonButton = MakeButton("Summon enemy", 220f, -287f, 370f, 44f, Summon);
			AddButtonHighlight(summonButton, "Action highlight");
			ColorBlock colors = ((Selectable)summonButton).colors;
			((ColorBlock)(ref colors)).normalColor = new Color(1.25f, 1.05f, 0.72f);
			((ColorBlock)(ref colors)).selectedColor = ((ColorBlock)(ref colors)).normalColor;
			((ColorBlock)(ref colors)).highlightedColor = new Color(1.45f, 1.22f, 0.82f);
			((ColorBlock)(ref colors)).pressedColor = new Color(0.95f, 0.76f, 0.48f);
			((ColorBlock)(ref colors)).disabledColor = new Color(0.5f, 0.5f, 0.5f, 0.65f);
			((Selectable)summonButton).colors = colors;
			((Component)summonButton).GetComponentInChildren<Text>().fontSize = 18;
			GUIManager.BlockInput(true);
			RefreshDetails();
			Send(0, target);
			nextPoll = Time.unscaledTime + 1f;
		}

		internal void ActivatorSuppressed(ZDOID piece)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			if (target == piece)
			{
				Close();
			}
		}

		internal void Close()
		{
			//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)
			if (Object.op_Implicit((Object)(object)panel))
			{
				Object.Destroy((Object)(object)panel);
				GUIManager.BlockInput(false);
			}
			panel = null;
			content = null;
			enemyScroll = null;
			snapshot = null;
			reserveFill = null;
			selectedIcon = null;
			target = ZDOID.None;
			rows.Clear();
			rowPrefabs.Clear();
			icons.Clear();
			starButtons.Clear();
			commandPending = false;
		}

		internal void Receive(MenuSnapshot incoming)
		{
			//IL_0023: 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_0163: Unknown result type (might be due to invalid IL or missing references)
			settings = incoming;
			if (((ZDOID)(ref incoming.Piece)).IsNone() || !Object.op_Implicit((Object)(object)panel) || incoming.Piece != target || incoming.Request < lastApplied)
			{
				return;
			}
			lastApplied = incoming.Request;
			snapshot = incoming;
			if (incoming.Request >= commandSerial)
			{
				commandPending = false;
			}
			if (!string.IsNullOrEmpty(incoming.Message))
			{
				Feedback(incoming.Message);
			}
			if (Object.op_Implicit((Object)(object)balanceText))
			{
				balanceText.text = "Reserve: " + ((decimal)incoming.Units / 1000000m).ToString("0.#", CultureInfo.InvariantCulture) + " / " + incoming.Capacity + "  •  +" + incoming.Regeneration.ToString("0.##", CultureInfo.InvariantCulture) + " tokens/minute";
			}
			if (Object.op_Implicit((Object)(object)reserveFill))
			{
				((Graphic)reserveFill).rectTransform.sizeDelta = new Vector2(810f * Mathf.Clamp01((float)incoming.Units / (1000000f * (float)Math.Max(1, incoming.Capacity))), 5f);
			}
			string text = incoming.LatestTier + "|" + string.Join("|", incoming.Rows.Select((MenuRow row) => row.Prefab + ":" + string.Join(",", row.Costs)));
			if (text != listSignature)
			{
				listSignature = text;
				int value = biome.value;
				biome.ClearOptions();
				List<string> list = new List<string> { "All unlocked biomes" };
				list.AddRange(ArenaRules.Biomes.Take(incoming.LatestTier + 1));
				biome.AddOptions(list);
				biome.SetValueWithoutNotify(Math.Min(value, list.Count - 1));
				if (!incoming.Rows.Any((MenuRow row) => row.Prefab == selected))
				{
					selected = incoming.Rows.FirstOrDefault()?.Prefab ?? "";
				}
				RebuildList();
			}
			RefreshDetails();
		}

		private void RebuildList()
		{
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0474: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_042a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0431: Unknown result type (might be due to invalid IL or missing references)
			//IL_0332: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_038a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0394: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)content) || snapshot == null)
			{
				return;
			}
			foreach (GameObject row in rows)
			{
				row.SetActive(false);
				Object.Destroy((Object)(object)row);
			}
			rows.Clear();
			rowPrefabs.Clear();
			InputField? obj = search;
			string query = ((obj != null) ? obj.text.Trim() : null) ?? "";
			List<MenuRow> list = snapshot.Rows.Where((MenuRow row) => (biome.value == 0 || row.Tier == biome.value - 1) && (Localized(row.Name).IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0 || row.Prefab.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0)).ToList();
			int num = 0;
			foreach (MenuRow item in list)
			{
				MenuRow captured = item;
				GameObject val = GUIManager.Instance.CreateButton("", content.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, (float)(-36 - num * 64)), 386f, 58f);
				val.GetComponent<Image>().sprite = null;
				Button component = val.GetComponent<Button>();
				ColorBlock colors = ((Selectable)component).colors;
				((ColorBlock)(ref colors)).normalColor = Color.white;
				((ColorBlock)(ref colors)).highlightedColor = new Color(1.18f, 1.18f, 1.18f);
				((ColorBlock)(ref colors)).selectedColor = Color.white;
				((ColorBlock)(ref colors)).pressedColor = new Color(0.82f, 0.82f, 0.82f);
				((ColorBlock)(ref colors)).fadeDuration = 0.12f;
				((Selectable)component).colors = colors;
				Frame(val.transform, "Row border", 386f, 58f, RowBorder);
				((Component)val.GetComponentInChildren<Text>()).gameObject.SetActive(false);
				Image val2 = Surface(val.transform, "Icon backing", -156f, 0f, 48f, 48f, new Color(0.025f, 0.03f, 0.04f));
				Sprite val3 = EnemyIcon(item.Prefab);
				if (Object.op_Implicit((Object)(object)val3))
				{
					Image obj2 = Surface(((Component)val2).transform, "Trophy icon", 0f, 0f, 44f, 44f, Color.white);
					obj2.sprite = val3;
					obj2.preserveAspect = true;
				}
				else
				{
					Silhouette(((Component)val2).transform, 0f, 0f, 36f);
				}
				Text obj3 = ChildLabel(val.transform, SelectedHeading(item), 22f, 9f, 252f, 35f, 18, new Color(0.98f, 0.94f, 0.84f));
				obj3.resizeTextForBestFit = true;
				obj3.resizeTextMinSize = 15;
				obj3.resizeTextMaxSize = 18;
				ChildLabel(val.transform, ArenaRules.Biomes[item.Tier] + (item.Aquatic ? "  •  Water" : ""), 22f, -19f, 252f, 18f, 13, Muted).font = GUIManager.Instance.AveriaSerif;
				Surface(val.transform, "Selection marker", -191f, 0f, 4f, 56f, Gold);
				((UnityEvent)val.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
				{
					selected = captured.Prefab;
					RefreshDetails();
				});
				rows.Add(val);
				rowPrefabs[val] = item.Prefab;
				num++;
			}
			if (num == 0)
			{
				Text val4 = ChildLabel(content.transform, "No enemies match your filters.", 0f, -55f, 345f, 60f, 18, Muted);
				RectTransform rectTransform = ((Graphic)val4).rectTransform;
				RectTransform rectTransform2 = ((Graphic)val4).rectTransform;
				Vector2 val5 = default(Vector2);
				((Vector2)(ref val5))..ctor(0.5f, 1f);
				rectTransform2.anchorMax = val5;
				rectTransform.anchorMin = val5;
				val4.alignment = (TextAnchor)4;
				rows.Add(((Component)val4).gameObject);
			}
			content.GetComponent<RectTransform>().sizeDelta = new Vector2(0f, Math.Max(426f, num * 64 + 14));
			if (Object.op_Implicit((Object)(object)enemyCount))
			{
				enemyCount.text = list.Count + ((list.Count == snapshot.Rows.Count) ? " opponents" : " shown");
			}
			if (Object.op_Implicit((Object)(object)enemyScroll))
			{
				enemyScroll.StopMovement();
				enemyScroll.verticalNormalizedPosition = 1f;
			}
			RefreshDetails();
		}

		private Sprite? EnemyIcon(string prefab)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Invalid comparison between Unknown and I4
			if (icons.TryGetValue(prefab, out Sprite value))
			{
				return value;
			}
			GameObject prefab2 = PrefabManager.Instance.GetPrefab(prefab);
			CharacterDrop val = (Object.op_Implicit((Object)(object)prefab2) ? prefab2.GetComponent<CharacterDrop>() : null);
			Sprite val2 = null;
			if (Object.op_Implicit((Object)(object)val))
			{
				foreach (Drop drop in val.m_drops)
				{
					ItemDrop val3 = (Object.op_Implicit((Object)(object)drop.m_prefab) ? drop.m_prefab.GetComponent<ItemDrop>() : null);
					if (Object.op_Implicit((Object)(object)val3) && (int)val3.m_itemData.m_shared.m_itemType == 13)
					{
						val2 = val3.m_itemData.GetIcon();
						if (Object.op_Implicit((Object)(object)val2))
						{
							break;
						}
					}
				}
			}
			icons[prefab] = val2;
			return val2;
		}

		private static bool EnemyDropsCoins(string prefabName)
		{
			GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab(prefabName) : null);
			CharacterDrop val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<CharacterDrop>() : null);
			if (Object.op_Implicit((Object)(object)val2))
			{
				return val2.m_drops.Any((Drop drop) => Object.op_Implicit((Object)(object)drop.m_prefab) && StringExtensionMethods.GetStableHashCode(((Object)drop.m_prefab).name) == Data.CoinPrefabHash);
			}
			return false;
		}

		private void RefreshDetails()
		{
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a7: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)panel))
			{
				return;
			}
			MenuRow menuRow = snapshot?.Rows.FirstOrDefault((MenuRow r) => r.Prefab == selected);
			if (Object.op_Implicit((Object)(object)selectedText))
			{
				selectedText.text = ((menuRow == null) ? "Select an enemy" : SelectedHeading(menuRow));
			}
			if (Object.op_Implicit((Object)(object)selectedBiome))
			{
				selectedBiome.text = ((menuRow == null) ? "Choose from the list" : (ArenaRules.Biomes[menuRow.Tier] + (menuRow.Aquatic ? "  •  Water arena" : "")));
			}
			if (Object.op_Implicit((Object)(object)selectedIcon))
			{
				selectedIcon.sprite = ((menuRow == null) ? null : EnemyIcon(menuRow.Prefab));
				((Behaviour)selectedIcon).enabled = (Object)(object)selectedIcon.sprite != (Object)null;
			}
			if (Object.op_Implicit((Object)(object)selectedFallback))
			{
				selectedFallback.SetActive(!Object.op_Implicit((Object)(object)selectedIcon) || !Object.op_Implicit((Object)(object)selectedIcon.sprite));
			}
			foreach (GameObject row in rows)
			{
				if (rowPrefabs.TryGetValue(row, out string value))
				{
					bool flag = value == selected;
					((Graphic)row.GetComponent<Image>()).color = (flag ? RowSelected : RowNormal);
					string[] frameEdges = FrameEdges;
					foreach (string text in frameEdges)
					{
						((Graphic)((Component)row.transform.Find("Row border " + text)).GetComponent<Image>()).color = (flag ? Gold : RowBorder);
					}
					((Component)row.transform.Find("Selection marker")).gameObject.SetActive(flag);
				}
			}
			for (int num2 = 0; num2 < starButtons.Count; num2++)
			{
				StyleChoice(starButtons[num2], stars == num2, num2 + ((num2 == 1) ? " star" : " stars"));
			}
			if (Object.op_Implicit((Object)(object)strengthText))
			{
				strengthText.text = DifficultyRules.Strength(strengthTenths).ToString("0.0", CultureInfo.InvariantCulture) + "x";
			}
			if (Object.op_Implicit((Object)(object)weakerButton))
			{
				((Selectable)weakerButton).interactable = strengthTenths > 10;
			}
			if (Object.op_Implicit((Object)(object)strongerButton))
			{
				((Selectable)strongerButton).interactable = strengthTenths < 30;
			}
			if (Object.op_Implicit((Object)(object)practiceButton))
			{
				StyleChoice(practiceButton, !loot, "Practice");
			}
			if (Object.op_Implicit((Object)(object)rewardsButton))
			{
				StyleChoice(rewardsButton, loot, "Loot rewards");
			}
			int num3 = menuRow?.Cost(stars, loot) ?? 0;
			if (Object.op_Implicit((Object)(object)quoteText))
			{
				quoteText.text = ((menuRow == null) ? "" : ((num3 == 0) ? "FREE" : (num3 + " tokens")));
			}
			if (Object.op_Implicit((Object)(object)detailText))
			{
				detailText.text = ((menuRow == null) ? "" : (((!loot) ? "No item drops or trophies." : (DifficultyRules.LootPercent(strengthTenths) + "% native loot • " + ((snapshot.LatestTier == menuRow.Tier) ? "Full price" : (Math.Min(100m, (decimal)Math.Max(0, snapshot.LatestTier - menuRow.Tier) * (decimal)snapshot.DiscountPerTier * 100m).ToString("0.##", CultureInfo.InvariantCulture) + "% discount")) + "\n" + ((snapshot.CoinLimitEnabled && EnemyDropsCoins(menuRow.Prefab)) ? ("Coins: " + snapshot.CoinAvailable + "/" + snapshot.CoinCapacity + " shared • +" + snapshot.CoinsPerHour.ToString("0.#") + "/hour") : "Item drops and trophies enabled."))) + (menuRow.Aquatic ? "\nRequires suitable water." : "")));
			}
			if (!Object.op_Implicit((Object)(object)summonButton))
			{
				return;
			}
			((Selectable)summonButton).interactable = menuRow != null && snapshot != null && snapshot.Phase == 0 && !commandPending && snapshot.Units >= (long)num3 * 1000000L;
			((Component)((Component)summonButton).transform.Find("Action highlight")).gameObject.SetActive(((Selectable)summonButton).interactable);
			((Graphic)((Component)summonButton).GetComponentInChildren<Text>()).color = (Color)(((Selectable)summonButton).interactable ? new Color(1f, 0.94f, 0.78f) : Muted);
			Text componentInChildren = ((Component)summonButton).GetComponentInChildren<Text>();
			object text2;
			if (!commandPending)
			{
				MenuSnapshot? menuSnapshot = snapshot;
				if (menuSnapshot == null || menuSnapshot.Phase != 1)
				{
					MenuSnapshot? menuSnapshot2 = snapshot;
					text2 = ((menuSnapshot2 != null && menuSnapshot2.Phase == 2) ? "Encounter active" : "Summon enemy");
				}
				else
				{
					text2 = "Counting down…";
				}
			}
			else
			{
				text2 = "Requesting…";
			}
			componentInChildren.text = (string)text2;
		}

		private void ChangeStrength(int direction)
		{
			strengthTenths = Math.Max(10, Math.Min(30, strengthTenths + direction));
			RefreshDetails();
		}

		private void Summon()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			if (snapshot != null && !commandPending && snapshot.Rows.Any((MenuRow row) => row.Prefab == selected))
			{
				commandPending = true;
				commandStarted = Time.unscaledTime;
				commandSerial = serial + 1;
				Send(1, target);
				RefreshDetails();
			}
		}

		private void Send(int operation, ZDOID piece)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (ZRoutedRpc.instance != null)
			{
				ZPackage val = new ZPackage();
				val.Write(2);
				val.Write(piece);
				val.Write(++serial);
				val.Write(operation);
				val.Write((operation == 1) ? selected : "");
				val.Write(stars);
				val.Write(loot);
				val.Write(strengthTenths);
				ZRoutedRpc.instance.InvokeRoutedRPC("ArenaCombat.Request.v1", new object[1] { val });
			}
		}

		private void Feedback(string text)
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				((Character)Player.m_localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false);
			}
		}

		private static string Localized(string text)
		{
			if (Localization.instance == null)
			{
				return text;
			}
			return Localization.instance.Localize(text);
		}

		private static string SelectedHeading(MenuRow row)
		{
			string text = Localized(row.Name);
			string text2 = " — " + ArenaRules.Biomes[row.Tier];
			if (!text.EndsWith(text2, StringComparison.Ordinal))
			{
				return text;
			}
			return text.Substring(0, text.Length - text2.Length);
		}

		private Text Label(string text, float x, float y, float width, float height, int size)
		{
			//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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			Text component = GUIManager.Instance.CreateText(text, panel.transform, Center, Center, new Vector2(x, y), GUIManager.Instance.AveriaSerifBold, size, GUIManager.Instance.ValheimBeige, true, Color.black, width, height, false).GetComponent<Text>();
			component.alignment = (TextAnchor)4;
			component.horizontalOverflow = (HorizontalWrapMode)0;
			component.verticalOverflow = (VerticalWrapMode)0;
			((Graphic)component).raycastTarget = false;
			return component;
		}

		private Button MakeButton(string text, float x, float y, float width, float height, Action click)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			Button component = GUIManager.Instance.CreateButton(text, panel.transform, Center, Center, new Vector2(x, y), width, height).GetComponent<Button>();
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				click();
			});
			return component;
		}

		private static void AddButtonHighlight(Button button, string name)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = ((Component)button).GetComponent<RectTransform>();
			Transform transform = ((Component)button).transform;
			Rect rect = component.rect;
			float width = ((Rect)(ref rect)).width;
			rect = component.rect;
			Image obj = Surface(transform, name, 0f, 0f, width, ((Rect)(ref rect)).height, new Color(1f, 0.82f, 0.44f, 0.85f));
			obj.sprite = GUIManager.Instance.GetSprite("button_highlight");
			obj.type = (Type)1;
			((Component)obj).transform.SetAsFirstSibling();
			((Component)obj).gameObject.SetActive(false);
		}

		private static void StyleChoice(Button button, bool selected, string text)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_0064: 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_007f: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			ColorBlock colors = ((Selectable)button).colors;
			((ColorBlock)(ref colors)).normalColor = (selected ? new Color(1.15f, 1.02f, 0.75f) : new Color(0.7f, 0.73f, 0.76f));
			((ColorBlock)(ref colors)).selectedColor = ((ColorBlock)(ref colors)).normalColor;
			((ColorBlock)(ref colors)).highlightedColor = (Color)(selected ? new Color(1.35f, 1.18f, 0.85f) : Color.white);
			((ColorBlock)(ref colors)).pressedColor = new Color(0.65f, 0.65f, 0.65f);
			((Selectable)button).colors = colors;
			((Component)((Component)button).transform.Find("Choice highlight")).gameObject.SetActive(selected);
			Text componentInChildren = ((Component)button).GetComponentInChildren<Text>();
			componentInChildren.text = (selected ? "✓ " : "") + text;
			((Graphic)componentInChildren).color = (Color)(selected ? new Color(1f, 0.9f, 0.65f) : Muted);
		}

		private static GameObject Silhouette(Transform parent, float x, float y, float size)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Expected O, but got Unknown
			GameObject val = new GameObject("Creature silhouette", new Type[2]
			{
				typeof(RectTransform),
				typeof(CreatureSilhouette)
			})
			{
				layer = 5
			};
			val.transform.SetParent(parent, false);
			RectTransform component = val.GetComponent<RectTransform>();
			Vector2 anchorMin = (component.anchorMax = Center);
			component.anchorMin = anchorMin;
			component.anchoredPosition = new Vector2(x, y);
			component.sizeDelta = new Vector2(size, size);
			CreatureSilhouette component2 = val.GetComponent<CreatureSilhouette>();
			((Graphic)component2).color = new Color(0.62f, 0.66f, 0.69f);
			((Graphic)component2).raycastTarget = false;
			return val;
		}

		private Text ChildLabel(Transform parent, string text, float x, float y, float width, float height, int size, Color color)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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)
			Text component = GUIManager.Instance.CreateText(text, parent, Center, Center, new Vector2(x, y), GUIManager.Instance.AveriaSerifBold, size, color, true, Color.black, width, height, false).GetComponent<Text>();
			component.alignment = (TextAnchor)3;
			component.horizontalOverflow = (HorizontalWrapMode)0;
			component.verticalOverflow = (VerticalWrapMode)0;
			((Graphic)component).raycastTarget = false;
			return component;
		}

		private static Image Surface(Transform parent, string name, float x, float y, float width, float height, Color color)
		{
			//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_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			})
			{
				layer = 5
			};
			val.transform.SetParent(parent, false);
			Image component = val.GetComponent<Image>();
			((Graphic)component).color = color;
			((Graphic)component).raycastTarget = false;
			RectTransform rectTransform = ((Graphic)component).rectTransform;
			Vector2 anchorMin = (rectTransform.anchorMax = Center);
			rectTransform.anchorMin = anchorMin;
			rectTransform.sizeDelta = new Vector2(width, height);
			rectTransform.anchoredPosition = new Vector2(x, y);
			return component;
		}

		private static void Frame(Transform parent, string name, float width, float height, Color color)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			Surface(parent, name + " Top", 0f, (height - 1f) / 2f, width, 1f, color);
			Surface(parent, name + " Bottom", 0f, (0f - (height - 1f)) / 2f, width, 1f, color);
			Surface(parent, name + " Left", (0f - (width - 1f)) / 2f, 0f, 1f, height, color);
			Surface(parent, name + " Right", (width - 1f) / 2f, 0f, 1f, height, color);
		}

		private static void Divider(Transform parent, string name, float x, float y, float width, bool ornament)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			Surface(parent, name, x, y, width, 1f, new Color(Gold.r, Gold.g, Gold.b, 0.65f));
			if (ornament)
			{
				((Transform)((Graphic)Surface(parent, name + " Diamond", x, y, 6f, 6f, Gold)).rectTransform).localRotation = Quaternion.Euler(0f, 0f, 45f);
			}
		}

		private void CreateScrollArea()
		{
			//IL_0038: 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_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Expected O, but got Unknown
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_0329: Unknown result type (might be due to invalid IL or missing references)
			//IL_032d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Unknown result type (might be due to invalid IL or missing references)
			//IL_036e: Unknown result type (might be due to invalid IL or missing references)
			Image val = Surface(((Component)Surface(panel.transform, "Enemy list border", -220f, -51.5f, 430f, 527f, new Color(0.64f, 0.48f, 0.26f, 0.75f))).transform, "Enemy list inset", 0f, 0f, 426f, 523f, new Color(0.025f, 0.03f, 0.04f));
			Surface(((Component)val).transform, "List heading", 0f, 243.5f, 422f, 36f, new Color(0.11f, 0.13f, 0.15f));
			ChildLabel(((Component)val).transform, "CHOOSE OPPONENT", -91f, 243.5f, 220f, 24f, 14, Gold);
			enemyCount = ChildLabel(((Component)val).transform, "", 141f, 243.5f, 116f, 24f, 13, Muted);
			enemyCount.alignment = (TextAnchor)5;
			Divider(((Component)val).transform, "List heading divider", 0f, 225.5f, 410f, ornament: false);
			enemyScroll = ((Component)val).gameObject.AddComponent<ScrollRect>();
			Image val2 = Surface(((Component)val).transform, "Viewport", -10f, -36.5f, 398f, 426f, Color.white);
			((Graphic)val2).raycastTarget = true;
			((Component)val2).gameObject.AddComponent<Mask>().showMaskGraphic = false;
			content = new GameObject("Enemies", new Type[1] { typeof(RectTransform) });
			content.layer = 5;
			content.transform.SetParent(((Component)val2).transform, false);
			RectTransform component = content.GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 1f);
			component.anchorMax = new Vector2(1f, 1f);
			component.pivot = new Vector2(0.5f, 1f);
			component.anchoredPosition = Vector2.zero;
			Image obj = Surface(((Component)val).transform, "Scrollbar track", 201f, -36.5f, 12f, 422f, new Color(0f, 0f, 0f, 0.65f));
			((Graphic)obj).raycastTarget = true;
			Scrollbar val3 = ((Component)obj).gameObject.AddComponent<Scrollbar>();
			Image val4 = Surface(((Component)obj).transform, "Scrollbar handle", 0f, 0f, 0f, 0f, Gold);
			((Graphic)val4).raycastTarget = true;
			((Graphic)val4).rectTransform.anchorMin = Vector2.zero;
			((Graphic)val4).rectTransform.anchorMax = Vector2.one;
			((Graphic)val4).rectTransform.offsetMin = new Vector2(2f, 2f);
			((Graphic)val4).rectTransform.offsetMax = new Vector2(-2f, -2f);
			val3.handleRect = ((Graphic)val4).rectTransform;
			((Selectable)val3).targetGraphic = (Graphic)(object)val4;
			val3.direction = (Direction)2;
			ColorBlock colors = ((Selectable)val3).colors;
			((ColorBlock)(ref colors)).normalColor = Color.white;
			((ColorBlock)(ref colors)).highlightedColor = new Color(1.15f, 1.15f, 1.15f);
			((ColorBlock)(ref colors)).pressedColor = new Color(0.8f, 0.8f, 0.8f);
			((Selectable)val3).colors = colors;
			enemyScroll.viewport = ((Graphic)val2).rectTransform;
			enemyScroll.content = component;
			enemyScroll.horizontal = false;
			enemyScroll.vertical = true;
			enemyScroll.movementType = (MovementType)2;
			enemyScroll.scrollSensitivity = 320f;
			enemyScroll.verticalScrollbar = val3;
			enemyScroll.verticalScrollbarVisibility = (ScrollbarVisibility)0;
		}
	}
	internal sealed class ArenaServer
	{
		internal const string RequestRpc = "ArenaCombat.Request.v1";

		internal const string ReplyRpc = "ArenaCombat.Reply.v1";

		internal const string DefeatRpc = "ArenaCombat.PlayerDefeated.v1";

		private readonly Plugin plugin;

		private ZRoutedRpc? boundRpc;

		private ZDOMan? boundWorld;

		private Catalogue? catalogue;

		private string catalogueSettings = "";

		private readonly Dictionary<string, ZDOID> controllers = new Dictionary<string, ZDOID>(StringComparer.Ordinal);

		private readonly Dictionary<ZDOID, ZDOID> controllersByPiece = new Dictionary<ZDOID, ZDOID>();

		private readonly HashSet<ZDOID> creatures = new HashSet<ZDOID>();

		private readonly DeathPresenceTracker<ZDOID> deaths = new DeathPresenceTracker<ZDOID>();

		private readonly Dictionary<long, float> requestTimes = new Dictionary<long, float>();

		private float nextScan;

		private float nextTick;

		private float nextPresenceTick;

		private bool loaded;

		private static readonly FieldInfo WorldObjects = AccessTools.Field(typeof(ZDOMan), "m_objectsByID");

		private readonly Dictionary<ZDOID, PresenceGrace> presence = new Dictionary<ZDOID, PresenceGrace>();

		internal const string CoinPayoutRpc = "ArenaCombat.CoinPayout.v1";

		private readonly Dictionary<ZDOID, CoinSource> coinSources = new Dictionary<ZDOID, CoinSource>();

		private ZDOID coinBankId = ZDOID.None;

		private CoinAllowance? coinAllowance;

		private Settings Settings => plugin.Settings;

		internal ArenaServer(Plugin plugin)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			this.plugin = plugin;
		}

		internal void Update()
		{
			if (ZRoutedRpc.instance != null && boundRpc != ZRoutedRpc.instance)
			{
				boundRpc = ZRoutedRpc.instance;
				boundRpc.Register<ZPackage>("ArenaCombat.Request.v1", (Action<long, ZPackage>)Request);
				boundRpc.Register<ZPackage>("ArenaCombat.Reply.v1", (Action<long, ZPackage>)Reply);
				boundRpc.Register<ZPackage>("ArenaCombat.CoinPayout.v1", (Action<long, ZPackage>)CoinPayout);
				boundRpc.Register<ZPackage>("ArenaCombat.PlayerDefeated.v1", (Action<long, ZPackage>)PlayerDefeated);
				controllers.Clear();
				controllersByPiece.Clear();
				creatures.Clear();
				requestTimes.Clear();
				boundWorld = null;
				catalogue = null;
				loaded = false;
				presence.Clear();
				deaths.Clear();
				ResetCoinWorld();
			}
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer() || !Object.op_Implicit((Object)(object)ZNetScene.instance) || ZDOMan.instance == null || !Object.op_Implicit((Object)(object)ZoneSystem.instance))
			{
				return;
			}
			if (boundWorld != ZDOMan.instance)
			{
				boundWorld = ZDOMan.instance;
				loaded = false;
				catalogue = null;
				controllers.Clear();
				controllersByPiece.Clear();
				creatures.Clear();
				presence.Clear();
				deaths.Clear();
				ResetCoinWorld();
				nextScan = (nextTick = (nextPresenceTick = 0f));
			}
			try
			{
				if (Time.unscaledTime >= nextScan)
				{
					nextScan = Time.unscaledTime + 5f;
					Scan();
				}
				if (loaded && Time.unscaledTime >= nextTick)
				{
					nextTick = Time.unscaledTime + 0.1f;
					bool flag = Time.unscaledTime >= nextPresenceTick;
					if (flag)
					{
						nextPresenceTick = Time.unscaledTime + 1f;
					}
					Tick(flag);
				}
			}
			catch (Exception error)
			{
				plugin.Error(error);
			}
		}

		private void Scan()
		{
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Invalid comparison between Unknown and I4
			string text = Settings.TierOverrides.Value + "|" + Settings.ExcludedEnemies.Value;
			if (catalogue == null || text != catalogueSettings)
			{
				catalogue = new Catalogue(Settings);
				catalogueSettings = text;
			}
			ZDO[] array = ((Dictionary<ZDOID, ZDO>)WorldObjects.GetValue(ZDOMan.instance)).Values.ToArray();
			ZDO[] array2 = array;
			foreach (ZDO val in array2)
			{
				if (val.IsValid() && (Data.IsController(val) || Data.IsEnemy(val)))
				{
					Observe(val);
				}
			}
			array2 = array;
			foreach (ZDO val2 in array2)
			{
				if (val2.IsValid() && Data.IsActivator(val2))
				{
					EnsureController(val2);
				}
			}
			EnsureCoinBank();
			if (loaded)
			{
				return;
			}
			foreach (ZDO item in CurrentControllers())
			{
				EncounterState val3 = Data.Read(item);
				if ((int)val3.Phase == 1)
				{
					val3.Cancel(Settings.Capacity.Value);
					Data.Write(item, val3);
					item.Set("arena.remaining", 0);
				}
			}
			loaded = true;
		}

		internal void Observe(ZDO zdo)
		{
			//IL_00b5: 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_0055: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer() || !zdo.IsValid())
			{
				return;
			}
			if (Data.IsController(zdo))
			{
				string text = zdo.GetString("arena.key", "");
				if (!(text == ""))
				{
					ZDOID key = Data.PieceId(zdo);
					if (controllersByPiece.TryGetValue(key, out var value) && value != zdo.m_uid && ZDOMan.instance.GetZDO(value) != null)
					{
						SilentDestroy(zdo);
						return;
					}
					controllers[text] = zdo.m_uid;
					controllersByPiece[key] = zdo.m_uid;
				}
			}
			else if (Data.IsEnemy(zdo))
			{
				creatures.Add(zdo.m_uid);
				CacheCoinSource(zdo);
			}
		}

		private IEnumerable<ZDO> CurrentControllers()
		{
			ZDOID[] array = controllers.Values.ToArray();
			foreach (ZDOID val in array)
			{
				ZDO zDO = ZDOMan.instance.GetZDO(val);
				if (zDO != null && zDO.IsValid())
				{
					yield return zDO;
				}
			}
		}

		private ZDO? EnsureController(ZDO piece)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Expected O, but got Unknown
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Expected O, but got Unknown
			if (controllersByPiece.TryGetValue(piece.m_uid, out var value))
			{
				ZDO zDO = ZDOMan.instance.GetZDO(value);
				if (zDO != null)
				{
					return zDO;
				}
				controllersByPiece.Remove(piece.m_uid);
			}
			if (Settings.AdminBuildOnly.Value && !IsAuthorizedBuilder(piece))
			{
				plugin.Warn("Removed an unauthorized Arena Coordinator: its original builder is not recognized as a server admin.");
				SilentDestroy(piece);
				return null;
			}
			if (Settings.MaximumActivators.Value > 0 && controllersByPiece.Count >= Settings.MaximumActivators.Value)
			{
				plugin.Warn("Removed an over-limit Arena Coordinator: the world placement limit has been reached.");
				SilentDestroy(piece);
				return null;
			}
			ZDO val = ZDOMan.instance.CreateNewZDO(piece.GetPosition(), StringExtensionMethods.GetStableHashCode("ArenaCombat_Reserve"));
			val.SetPrefab(StringExtensionMethods.GetStableHashCode("ArenaCombat_Reserve"));
			val.Persistent = true;
			val.Type = (ObjectType)2;
			val.SetRotation(piece.GetRotation());
			val.SetConnection((ConnectionType)3, piece.m_uid);
			val.Set("arena.key", Guid.NewGuid().ToString("N"));
			Data.Write(val, new EncounterState(new ReserveBank(0L, Data.Now, 0), (EncounterPhase)0, 0L));
			Observe(val);
			return val;
		}

		private unsafe bool IsAuthorizedBuilder(ZDO piece)
		{
			//IL_00cd: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
			long creator = piece.GetLong(ZDOVars.s_creator, 0L);
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && ZNet.instance.IsServer() && creator != 0L && creator == Player.m_localPlayer.GetPlayerID())
			{
				return true;
			}
			ZNetPeer val = (ZNetPeer)((creator != 0L) ? ((object)((IEnumerable<ZNetPeer>)ZNet.instance.GetPeers()).FirstOrDefault((Func<ZNetPeer, bool>)((ZNetPeer peer) => peer.IsReady() && peer.m_playerID == creator))) : ((object)ZNet.instance.GetPeer(((ZDOID)(ref piece.m_uid)).UserID)));
			if (val != null)
			{
				return IsAdmin(val.m_uid);
			}
			int num = piece.GetInt(ZDOVars.s_creatorIndex, -1);
			if (num >= 0 && ZNet.World != null && num < ZNet.World.m_playerHistory.Count)
			{
				PlatformUserID id = ZNet.World.m_playerHistory[num].m_id;
				if (((PlatformUserID)(ref id)).IsValid)
				{
					return ZNet.instance.IsAdmin(((object)(*(PlatformUserID*)(&id))/*cast due to .constrained prefix*/).ToString());
				}
			}
			if (creator == 0L)
			{
				return ((ZDOID)(ref piece.m_uid)).UserID == ZDOMan.GetSessionID();
			}
			return false;
		}

		private bool IsAdmin(long peerId)
		{
			if (peerId == ZDOMan.GetSessionID())
			{
				return true;
			}
			ZNetPeer peer = ZNet.instance.GetPeer(peerId);
			if (peer != null)
			{
				return ZNet.instance.IsAdmin(peer.m_socket.GetHostName());
			}
			return false;
		}

		private ZDOID CharacterForPeer(long sender)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			if (sender == ZDOMan.GetSessionID())
			{
				return ZNet.instance.LocalPlayerCharacterID;
			}
			ZNetPeer peer = ZNet.instance.GetPeer(sender);
			if (peer == null || !peer.IsReady())
			{
				return ZDOID.None;
			}
			return peer.m_characterID;
		}

		private ZDO? PlayerForPeer(long sender)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = ZDOMan.instance.GetZDO(CharacterForPeer(sender));
			if (zDO == null || !(zDO.GetFloat(ZDOVars.s_health, 100f) > 0f) || zDO.GetBool(ZDOVars.s_dead, false))
			{
				return null;
			}
			return zDO;
		}

		internal void ReportPlayerDeath(ZDOID victim, ZDOID attacker, SpawnTag tag)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Expected O, but got Unknown
			//IL_000f: 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)
			if (ZRoutedRpc.instance != null)
			{
				ZPackage val = new ZPackage();
				val.Write(victim);
				val.Write(attacker);
				val.Write(tag.Home);
				val.Write(tag.Encounter);
				ZRoutedRpc.instance.InvokeRoutedRPC("ArenaCombat.PlayerDefeated.v1", new object[1] { val });
			}
		}

		private List<ZDO> LivingPlayers()
		{
			long now = Data.Now;
			deaths.Prune(now);
			return (from player in ZNet.instance.GetAllCharacterZDOS()
				where deaths.IsAlive(player.m_uid, player.GetFloat(ZDOVars.s_health, 100f) > 0f && !player.GetBool(ZDOVars.s_dead, false), now)
				select player).ToList();
		}

		private void PlayerDefeated(long sender, ZPackage p)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: 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_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer() || ZDOMan.instance == null || !Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				return;
			}
			try
			{
				ZDOID val = p.ReadZDOID();
				ZDOID val2 = p.ReadZDOID();
				string text = p.ReadString();
				string text2 = p.ReadString();
				if (text.Length == 0 || text.Length > 80 || text2.Length == 0 || text2.Length > 80 || ((ZDOID)(ref val)).IsNone() || val != CharacterForPeer(sender))
				{
					return;
				}
				ZDO zDO = ZDOMan.instance.GetZDO(val);
				ZDO attacker = ZDOMan.instance.GetZDO(val2);
				if (zDO == null || !zDO.IsValid() || zDO.GetOwner() != sender || !Data.IsEnemy(attacker) || attacker.GetBool("arena.suppress", false) || attacker.GetString("arena.home", "") != text || attacker.GetString("arena.encounter", "") != text2)
				{
					return;
				}
				if (!loaded)
				{
					Scan();
				}
				ZDOID value;
				ZDO val3 = (controllers.TryGetValue(text, out value) ? ZDOMan.instance.GetZDO(value) : null);
				if (val3 != null && !val3.GetBool("arena.suppress", false) && val3.GetInt("arena.phase", 0) == 2 && !(val3.GetString("arena.encounter", "") != text2))
				{
					deaths.Report(val, Data.Now);
					if (!LivingPlayers().Any((ZDO player) => Vector3.Distance(player.GetPosition(), attacker.GetPosition()) <= Settings.DefeatRadius.Value))
					{
						FinishDefeatedEncounter(val3, text, text2);
					}
				}
			}
			catch (Exception error)
			{
				plugin.Error(error);
			}
		}

		private void FinishDefeatedEncounter(ZDO controller, string home, string encounter)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			controller.SetOwner(ZDOMan.GetSessionID());
			EncounterState val = Data.Read(controller);
			val.Finish();
			Data.Write(controller, val);
			controller.Set("arena.remaining", 0);
			controller.Set("arena.empty", 0L);
			controller.Set("arena.pending", "");
			ZDO[] array = ((Dictionary<ZDOID, ZDO>)WorldObjects.GetValue(ZDOMan.instance)).Values.Where((ZDO z) => z.IsValid() && Data.IsEnemy(z) && z.GetString("arena.home", "") == home && z.GetString("arena.encounter", "") == encounter).ToArray();
			foreach (ZDO val2 in array)
			{
				SilentDestroy(val2);
				presence.Remove(val2.m_uid);
				creatures.Remove(val2.m_uid);
			}
			plugin.LogInfo("Arena encounter ended after player defeat: no surviving player in range.");
		}

		private void Request(long sender, ZPackage p)
		{
			//IL_03e4: 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)
			//IL_0031: 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_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer() || ZDOMan.instance == null || !Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				return;
			}
			ZDOID val = ZDOID.None;
			int serial = 0;
			try
			{
				if (p.ReadInt() != 2)
				{
					return;
				}
				val = p.ReadZDOID();
				serial = p.ReadInt();
				int num = p.ReadInt();
				string text = p.ReadString();
				int num2 = p.ReadInt();
				bool flag = p.ReadBool();
				int num3 = p.ReadInt();
				if (text.Length > 160 || (num != 0 && num != 1 && num != 2))
				{
					return;
				}
				long key = sender ^ ((num == 1) ? long.MinValue : 0);
				if (requestTimes.TryGetValue(key, out var value) && Time.unscaledTime - value < 0.2f)
				{
					return;
				}
				requestTimes[key] = Time.unscaledTime;
				if (num == 2)
				{
					if (sender == ZDOMan.GetSessionID() || ZNet.instance.GetPeer(sender) != null)
					{
						if (!loaded)
						{
							Scan();
						}
						Respond(sender, ZDOID.None, serial, null, "");
					}
					return;
				}
				ZDO val2 = PlayerForPeer(sender);
				ZDO zDO = ZDOMan.instance.GetZDO(val);
				if (val2 == null || zDO == null || !Data.IsActivator(zDO) || Vector3.Distance(val2.GetPosition(), zDO.GetPosition()) > Settings.InteractDistance.Value)
				{
					Respond(sender, val, serial, null, "Move closer to the Arena Coordinator.");
					return;
				}
				if (!loaded)
				{
					Scan();
				}
				ZDO val3 = EnsureController(zDO);
				if (val3 == null)
				{
					Respond(sender, val, serial, null, "Arena Coordinator unavailable.");
					return;
				}
				if (val3.GetLong("arena.hiddenUntil", 0L) > Data.WorldNow)
				{
					Respond(sender, val, serial, val3, "Arena Coordinator is briefly inactive after spawning.");
					return;
				}
				EncounterState val4 = Data.Read(val3);
				val4.Bank.Refill(Data.Now, Settings.Capacity.Value, (decimal)Settings.Regeneration.Value);
				string message = "";
				if (num == 1)
				{
					int num4 = ArenaRules.LatestTier((Func<string, bool>)ZoneSystem.instance.GetGlobalKey);
					if (!DifficultyRules.IsValid(num3) || num2 < 0 || num2 > 2 || !catalogue.Enemies.TryGetValue(text, out EnemyDefinition value2) || value2.Tier > num4 || value2.Template.GetComponent<Character>().m_boss)
					{
						message = "That enemy, star level, or strength is unavailable.";
					}
					else
					{
						int num5 = ArenaRules.Cost(Settings.BaseCost(num2), Settings.LootCost.Value, flag, num4, value2.Tier, (decimal)Settings.Discount.Value);
						if ((int)val4.Phase != 0)
						{
							message = "This Arena Coordinator already has an encounter.";
						}
						else if (!val4.TryBegin(num5, Data.Now, Settings.Countdown.Value))
						{
							message = "Not enough reserve tokens.";
						}
						else
						{
							val3.Set("arena.pending", text);
							val3.Set("arena.stars", num2);
							val3.Set("arena.strengthTenths", num3);
							val3.Set("arena.lootPercent", DifficultyRules.LootPercent(num3));
							val3.Set("arena.loot", flag);
							val3.Set("arena.encounter", Guid.NewGuid().ToString("N"));
							val3.Set("arena.remaining", Settings.Countdown.Value);
							val3.Set("arena.empty", 0L);
							message = "Summon reserved. Prepare for battle!";
						}
					}
				}
				Data.Write(val3, val4);
				Respond(sender, val, serial, val3, message);
			}
			catch (Exception error)
			{
				plugin.Error(error);
				if (!((ZDOID)(ref val)).IsNone())
				{
					Respond(sender, val, serial, null, "The summon could not be processed.");
				}
			}
		}

		private void Respond(long sender, ZDOID piece, int serial, ZDO? controller, string message)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			RefillCoinBank();
			MenuSnapshot s = new MenuSnapshot
			{
				Piece = piece,
				Request = serial,
				LatestTier = ArenaRules.LatestTier((Func<string, bool>)ZoneSystem.instance.GetGlobalKey),
				Capacity = Settings.Capacity.Value,
				Regeneration = Settings.Regeneration.Value,
				DiscountPerTier = Settings.Discount.Value,
				CoinLimitEnabled = Settings.CoinLimitEnabled.Value,
				CoinAvailable = coinAllowance.Available,
				CoinCapacity = Settings.CoinCapacity.Value,
				CoinsPerHour = Settings.CoinsPerHour.Value,
				Radius = Settings.Radius.Value,
				InteractionDistance = Settings.InteractDistance.Value,
				Grace = Settings.Grace.Value,
				AdminBuildOnly = Settings.AdminBuildOnly.Value,
				Invulnerable = Settings.Invulnerable.Value,
				BuilderIsAdmin = IsAdmin(sender),
				Count = controllersByPiece.Count,
				Maximum = Settings.MaximumActivators.Value,
				Message = message
			};
			if (controller != null)
			{
				s.Units = controller.GetLong("arena.units", 0L);
				s.Phase = controller.GetInt("arena.phase", 0);
				s.Remaining = controller.GetInt("arena.remaining", 0);
				s.CurrentEnemy = controller.GetString("arena.pending", "");
				foreach (EnemyDefinition item in (from e in catalogue.Enemies.Values
					where e.Tier <= s.LatestTier
					orderby e.Tier descending
					select e).ThenBy<EnemyDefinition, string>((EnemyDefinition e) => e.Name, StringComparer.Ordinal))
				{
					MenuRow menuRow = new MenuRow
					{
						Prefab = item.Prefab,
						Name = item.Name,
						Tier = item.Tier,
						Aquatic = item.Aquatic
					};
					for (int num = 0; num <= 2; num++)
					{
						for (int num2 = 0; num2 <= 1; num2++)
						{
							menuRow.Costs[num * 2 + num2] = ArenaRules.Cost(Settings.BaseCost(num), Settings.LootCost.Value, num2 == 1, s.LatestTier, item.Tier, (decimal)Settings.Discount.Value);
						}
					}
					s.Rows.Add(menuRow);
				}
			}
			boundRpc.InvokeRoutedRPC(sender, "ArenaCombat.Reply.v1", new object[1] { s.Pack() });
		}

		private void Reply(long sender, ZPackage p)
		{
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || boundRpc == null)
			{
				return;
			}
			long num = (ZNet.instance.IsServer() ? ZDOMan.GetSessionID() : (from peer in ZNet.instance.GetPeers()
				where peer.m_server
				select peer.m_uid).FirstOrDefault());
			if (sender != num || num == 0L)
			{
				return;
			}
			try
			{
				plugin.Menu.Receive(MenuSnapshot.Unpack(p));
			}
			catch (Exception error)
			{
				plugin.Error(error);
			}
		}

		private void Tick(bool checkPresence)
		{
			//IL_0039: 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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: 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_035d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0363: Invalid comparison between Unknown and I4
			//IL_0591: Unknown result type (might be due to invalid IL or missing references)
			//IL_0596: Unknown result type (might be due to invalid IL or missing references)
			//IL_059e: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bf: Invalid comparison between Unknown and I4
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0470: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Expected O, but got Unknown
			//IL_01e4: Expected O, but got Unknown
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			long now = Data.Now;
			List<ZDO> source = LivingPlayers();
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
			ZDOID[] array = (checkPresence ? creatures.ToArray() : Array.Empty<ZDOID>());
			foreach (ZDOID val in array)
			{
				ZDO enemy = ZDOMan.instance.GetZDO(val);
				if (enemy == null || !enemy.IsValid())
				{
					creatures.Remove(val);
					continue;
				}
				string key = enemy.GetString("arena.home", "");
				ZDOID value;
				ZDO val2 = (controllers.TryGetValue(key, out value) ? ZDOMan.instance.GetZDO(value) : null);
				bool num = val2 != null && !val2.GetBool("arena.suppress", false) && val2.GetInt("arena.phase", 0) == 2 && enemy.GetString("arena.encounter", "") == val2.GetString("arena.encounter", "");
				ZDO val3 = ((val2 == null) ? null : ZDOMan.instance.GetZDO(Data.PieceId(val2)));
				if (!num || val3 == null || enemy.GetBool("arena.suppress", false))
				{
					SilentDestroy(enemy);
					creatures.Remove(val);
					continue;
				}
				if (enemy.GetBool(ZDOVars.s_tamed, false))
				{
					plugin.Warn("Removed an arena creature with an unexpected tamed flag.");
					SilentDestroy(enemy);
					presence.Remove(val);
					creatures.Remove(val);
					continue;
				}
				if (!presence.TryGetValue(val, out PresenceGrace value2))
				{
					Dictionary<ZDOID, PresenceGrace> dictionary2 = presence;
					PresenceGrace val4 = new PresenceGrace(0L);
					value2 = val4;
					dictionary2[val] = val4;
				}
				if (value2.Check(source.Any((ZDO player) => Vector3.Distance(player.GetPosition(), enemy.GetPosition()) <= Settings.Radius.Value), now, Settings.Grace.Value))
				{
					SilentDestroy(enemy);
					presence.Remove(val);
					creatures.Remove(val);
				}
				else
				{
					dictionary[key] = ((!dictionary.TryGetValue(key, out var value3)) ? 1 : (value3 + 1));
				}
			}
			foreach (ZDO item in CurrentControllers())
			{
				if (item.GetBool("arena.suppress", false))
				{
					continue;
				}
				ZDO piece = ZDOMan.instance.GetZDO(Data.PieceId(item));
				if (piece == null || !Data.IsActivator(piece))
				{
					string key2 = item.GetString("arena.key", "");
					SilentDestroy(item);
					controllers.Remove(key2);
					controllersByPiece.Remove(Data.PieceId(item));
					continue;
				}
				item.SetOwner(ZDOMan.GetSessionID());
				EncounterState val5 = Data.Read(item);
				if (checkPresence)
				{
					val5.Bank.Refill(now, Settings.Capacity.Value, (decimal)Settings.Regeneration.Value);
				}
				if ((int)val5.Phase == 1)
				{
					item.Set("arena.remaining", (int)Math.Max(0.0, Math.Ceiling((double)(val5.DeadlineMs - now) / 1000.0)));
					if (val5.CanSpawn(now))
					{
						if (!source.Any((ZDO p) => Vector3.Distance(p.GetPosition(), piece.GetPosition()) <= Settings.Radius.Value))
						{
							val5.Cancel(Settings.Capacity.Value);
						}
						else
						{
							ZDO val6 = null;
							try
							{
								string key3 = item.GetString("arena.pending", "");
								int num2 = ArenaRules.LatestTier((Func<string, bool>)ZoneSystem.instance.GetGlobalKey);
								if (!catalogue.Enemies.TryGetValue(key3, out EnemyDefinition value4) || value4.Tier > num2)
								{
									throw new InvalidOperationException("Enemy no longer available.");
								}
								val6 = Spawn(piece, item, value4);
								val5.SpawnSucceeded();
								long num3 = Data.WorldNow + 5000;
								item.Set("arena.hiddenUntil", num3);
								Activator.Conceal(piece.m_uid, num3);
							}
							catch (Exception error)
							{
								if (val6 != null)
								{
									SilentDestroy(val6);
								}
								val5.Cancel(Settings.Capacity.Value);
								plugin.Error(error);
							}
						}
					}
				}
				else if ((int)val5.Phase == 2 && checkPresence)
				{
					string key4 = item.GetString("arena.key", "");
					if (dictionary.ContainsKey(key4))
					{
						item.Set("arena.empty", 0L);
					}
					else
					{
						long num4 = item.GetLong("arena.empty", 0L);
						if (num4 == 0L || num4 > now)
						{
							item.Set("arena.empty", now);
						}
						else if (now - num4 >= 3000)
						{
							val5.Finish();
							item.Set("arena.empty", 0L);
						}
					}
				}
				Data.Write(item, val5);
			}
			if (checkPresence)
			{
				PruneCoinSources();
			}
			array = presence.Keys.Where((ZDOID id) => !creatures.Contains(id)).ToArray();
			foreach (ZDOID key5 in array)
			{
				presence.Remove(key5);
			}
		}

		private ZDO Spawn(ZDO piece, ZDO controller, EnemyDefinition definition)
		{
			//IL_0001: 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_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = piece.GetPosition() + piece.GetRotation() * Settings.Offset;
			ZNetView component = definition.Template.GetComponent<ZNetView>();
			ZDO val2 = ZDOMan.instance.CreateNewZDO(val, StringExtensionMethods.GetStableHashCode(definition.Prefab));
			try
			{
				val2.SetPrefab(StringExtensionMethods.GetStableHashCode(definition.Prefab));
				val2.Persistent = true;
				val2.Type = component.m_type;
				val2.Distant = component.m_distant;
				val2.SetRotation(piece.GetRotation());
				int num = controller.GetInt("arena.stars", 0) + 1;
				val2.Set(ZDOVars.s_level, num, false);
				float num2 = definition.Template.GetComponent<Character>().GetMaxHealthBase() * (float)num * (float)DifficultyRules.Strength(Data.Strength(controller));
				val2.Set(ZDOVars.s_maxHealth, num2);
				val2.Set(ZDOVars.s_despawnInDay, false);
				val2.Set(ZDOVars.s_eventCreature, false);
				if (definition.Dvergr)
				{
					val2.Set(ZDOVars.s_aggravated, true);
					val2.Set(ZDOVars.s_huntPlayer, true);
				}
				SpawnTag.FromController(controller).Apply(val2);
				Observe(val2);
				return val2;
			}
			catch
			{
				SilentDestroy(val2);
				throw;
			}
		}

		internal static void SilentDestroy(ZDO zdo)
		{
			if (ZDOMan.instance != null && zdo.IsValid())
			{
				zdo.SetOwner(ZDOMan.GetSessionID());
				zdo.Set("arena.suppress", true);
				if (Data.IsEnemy(zdo))
				{
					Plugin.Instance?.Server.CacheCoinSource(zdo);
				}
				ZDOMan.instance.DestroyZDO(zdo);
			}
		}

		private void ResetCoinWorld()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			coinSources.Clear();
			coinBankId = ZDOID.None;
			coinAllowance = null;
		}

		internal void CacheCoinSource(ZDO zdo)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer() && Data.IsEnemy(zdo))
			{
				coinSources[zdo.m_uid] = new CoinSource(zdo);
			}
		}

		private void EnsureCoinBank()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = ZDOMan.instance.GetZDO(coinBankId);
			if (zDO != null && zDO.IsValid() && coinAllowance != null)
			{
				zDO.SetOwner(ZDOMan.GetSessionID());
				return;
			}
			ZDO val = ((IEnumerable<ZDO>)((Dictionary<ZDOID, ZDO>)WorldObjects.GetValue(ZDOMan.instance)).Values).FirstOrDefault((Func<ZDO, bool>)((ZDO z) => z.IsValid() && Data.IsCoinBank(z)));
			long now = Data.Now;
			if (val == null)
			{
				val = ZDOMan.instance.CreateNewZDO(Vector3.zero, StringExtensionMethods.GetStableHashCode("ArenaCombat_CoinAllowance"));
				val.SetPrefab(StringExtensionMethods.GetStableHashCode("ArenaCombat_CoinAllowance"));
				val.Persistent = true;
				val.Type = (ObjectType)2;
				val.Set("arena.units", (long)Settings.CoinCapacity.Value * 1000000L);
				val.Set("arena.updated", now);
			}
			val.SetOwner(ZDOMan.GetSessionID());
			Dictionary<string, CoinClaim> dictionary = new Dictionary<string, CoinClaim>(StringComparer.Ordinal);
			byte[] byteArray = val.GetByteArray("arena.coinClaims", (byte[])null);
			if (byteArray != null && byteArray.Length != 0)
			{
				ZPackage val2 = new ZPackage(byteArray);
				if (val2.ReadInt() != 1)
				{
					throw new InvalidOperationException("Unsupported saved coin allowance.");
				}
				int num = val2.ReadInt();
				if (num < 0 || num > 65536)
				{
					throw new InvalidOperationException("Invalid coin receipt count.");
				}
				for (int num2 = 0; num2 < num; num2++)
				{
					string text = val2.ReadString();
					int num3 = val2.ReadInt();
					long num4 = val2.ReadLong();
					if (text.Length > 160 || num3 < 0 || num3 > 10000)
					{
						throw new InvalidOperationException("Invalid coin receipt.");
					}
					dictionary[text] = new CoinClaim(num3, num4);
				}
			}
			coinBankId = val.m_uid;
			coinAllowance = new CoinAllowance(val.GetLong("arena.units", 0L), val.GetLong("arena.updated", now), val.GetLong("arena.coinRemainder", 0L), (IEnumerable<KeyValuePair<string, CoinClaim>>)dictionary);
		}

		private void RefillCoinBank()
		{
			EnsureCoinBank();
			coinAllowance.Refill(Data.Now, Settings.CoinCapacity.Value, (decimal)Settings.CoinsPerHour.Value);
			WriteCoinBank(receipts: false);
		}

		private void WriteCoinBank(bool receipts)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Expected O, but got Unknown
			//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)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = ZDOMan.instance.GetZDO(coinBankId);
			if (zDO == null || coinAllowance == null)
			{
				throw new InvalidOperationException("Coin allowance unavailable.");
			}
			zDO.SetOwner(ZDOMan.GetSessionID());
			zDO.Set("arena.units", coinAllowance.Units);
			zDO.Set("arena.updated", coinAllowance.UpdatedAtMs);
			zDO.Set("arena.coinRemainder", coinAllowance.Remainder);
			if (!receipts)
			{
				return;
			}
			ZPackage val = new ZPackage();
			val.Write(1);
			val.Write(coinAllowance.Claims.Count);
			foreach (KeyValuePair<string, CoinClaim> claim in coinAllowance.Claims)
			{
				val.Write(claim.Key);
				CoinClaim value = claim.Value;
				val.Write(((CoinClaim)(ref value)).Charged);
				value = claim.Value;
				val.Write(((CoinClaim)(ref value)).AtMs);
			}
			zDO.Set("arena.coinClaims", val.GetArray());
		}

		internal void RequestCoinPayout(SpawnTag tag, int amount, Vector3 position, bool cheated)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			ZDOID source = tag.Source;
			if (!((ZDOID)(ref source)).IsNone() && ZRoutedRpc.instance != null)
			{
				ZPackage val = new ZPackage();
				val.Write(tag.Source);
				val.Write(tag.Home);
				val.Write(tag.Encounter);
				val.Write(amount);
				val.Write(position);
				val.Write(cheated);
				ZRoutedRpc.instance.InvokeRoutedRPC("ArenaCombat.CoinPayout.v1", new object[1] { val });
			}
		}

		private unsafe void CoinPayout(long sender, ZPackage p)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer() || ZDOMan.instance == null || !Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				return;
			}
			try
			{
				ZDOID val = p.ReadZDOID();
				string text = p.ReadString();
				string text2 = p.ReadString();
				int num = p.ReadInt();
				Vector3 val2 = p.ReadVector3();
				bool flag = p.ReadBool();
				if (((ZDOID)(ref val)).IsNone() || text.Length == 0 || text.Length > 80 || text2.Length == 0 || text2.Length > 80 || num < 1 || num > 10000 || (sender != ZDOMan.GetSessionID() && ZNet.instance.GetPeer(sender) == null))
				{
					return;
				}
				if (!loaded)
				{
					Scan();
				}
				ZDO zDO = ZDOMan.instance.GetZDO(val);
				if (zDO != null && zDO.IsValid())
				{
					CacheCoinSource(zDO);
				}
				if (!coinSources.TryGetValue(val, out CoinSource value) || value.Owner != sender || !value.Loot || value.Suppressed || value.Home != text || value.Encounter != text2 || Data.Now < value.SeenAt || Data.Now - value.SeenAt >= 120000)
				{
					return;
				}
				ZDOID value2;
				ZDO val3 = (controllers.TryGetValue(text, out value2) ? ZDOMan.instance.GetZDO(value2) : null);
				if (val3 == null || val3.GetBool("arena.suppress", false) || val3.GetString("arena.encounter", "") != text2)
				{
					return;
				}
				if (!Finite(val2) || Vector3.Distance(val2, value.Position) > 100f)
				{
					val2 = value.Position + Vector3.up;
				}
				EnsureCoinBank();
				string text3 = ((object)(*(ZDOID*)(&val))/*cast due to .constrained prefix*/).ToString();
				int num2 = coinAllowance.Claim(text3, num, Data.Now, Settings.CoinCapacity.Value, (decimal)Settings.CoinsPerHour.Value, Settings.CoinLimitEnabled.Value);
				try
				{
					if (num2 > 0)
					{
						SpawnCoins(num2, val2, sender, flag || value.Cheated);
					}
				}
				catch
				{
					coinAllowance.Undo(text3, Settings.CoinCapacity.Value);
					WriteCoinBank(receipts: true);
					throw;
				}
				WriteCoinBank(receipts: true);
			}
			catch (Exception error)
			{
				plugin.Error(error);
			}
		}

		private static bool Finite(Vector3 value)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: 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_0034: 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)
			if (!float.IsNaN(value.x) && !float.IsNaN(value.y) && !float.IsNaN(value.z) && !float.IsInfinity(value.x) && !float.IsInfinity(value.y))
			{
				return !float.IsInfinity(value.z);
			}
			return false;
		}

		private static void SpawnCoins(int amount, Vector3 position, long owner, bool cheated)
		{
			//IL_0099: 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_00de: Unknown result type (might be due to invalid IL or missing references)
			GameObject prefab = ZNetScene.instance.GetPrefab(Data.CoinPrefabHash);
			ItemDrop val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent<ItemDrop>() : null);
			if (!Object.op_Implicit((Object)(object)val))
			{
				throw new InvalidOperationException("Native Coins prefab unavailable.");
			}
			ZNetView component = prefab.GetComponent<ZNetView>();
			List<ZDO> list = new List<ZDO>();
			try
			{
				int num = amount;
				while (num > 0)
				{
					ItemData val2 = val.m_itemData.Clone();
					val2.m_dropPrefab = prefab;
					val2.m_stack = Math.Min(num, Math.Max(1, val2.m_shared.m_maxStackSize));
					val2.m_worldLevel = (byte)Game.m_worldLevel;
					val2.m_cheated = cheated;
					ZDO val3 = ZDOMan.instance.CreateNewZDO(position, Data.CoinPrefabHash);
					list.Add(val3);
					val3.SetPrefab(Data.CoinPrefabHash);
					val3.Persistent = true;
					val3.Type = component.m_type;
					val3.Distant = component.m_distant;
					val3.SetRotation(Quaternion.identity);
					ItemDrop.SaveToZDO(val2, val3, -1);
					val3.SetOwner(owner);
					num -= val2.m_stack;
				}
			}
			catch
			{
				foreach (ZDO item in list)
				{
					SilentDestroy(item);
				}
				throw;
			}
		}

		private unsafe void PruneCoinSources()
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			long now = Data.Now;
			KeyValuePair<ZDOID, CoinSource>[] array = coinSources.Where<KeyValuePair<ZDOID, CoinSource>>((KeyValuePair<ZDOID, CoinSource> s) => ZDOMan.instance.GetZDO(s.Key) == null && (now < s.Value.SeenAt || now - s.Value.SeenAt >= 120000)).ToArray();
			foreach (KeyValuePair<ZDOID, CoinSource> keyValuePair in array)
			{
				coinSources.Remove(keyValuePair.Key);
			}
			if (coinAllowance != null && coinAllowance.Prune(now, (ISet<string>)new HashSet<string>(coinSources.Keys.Select((ZDOID id) => ((object)(*(ZDOID*)(&id))/*cast due to .constrained prefix*/).ToString()), StringComparer.Ordinal)))
			{
				WriteCoinBank(receipts: true);
			}
		}
	}
	internal sealed class EnemyDefinition
	{
		internal readonly string Prefab;

		internal readonly string Name;

		internal readonly int Tier;

		internal readonly GameObject Template;

		internal readonly bool Aquatic;

		internal readonly bool Dvergr;

		internal EnemyDefinition(GameObject prefab, int tier)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			Template = prefab;
			Prefab = ((Object)prefab).name;
			string name = prefab.GetComponent<Character>().m_name;
			Dvergr = (int)prefab.GetComponent<Character>().m_faction == 10;
			Name = (Dvergr ? RosterRules.DvergrName(Prefab, name) : RosterRules.BaseName(name));
			Tier = tier;
			Aquatic = Prefab == "Serpent" || Prefab == "BonemawSerpent" || Prefab == "Leech" || Prefab == "Leech_cave";
		}
	}
	internal sealed class Catalogue
	{
		internal readonly Dictionary<string, EnemyDefinition> Enemies = new Dictionary<string, EnemyDefinition>(StringComparer.Ordinal);

		private static readonly Dictionary<string, int> Known = BuildKnown();

		private static readonly HashSet<string> BossNames = new HashSet<string>(StringComparer.Ordinal) { "Eikthyr", "gd_king", "Bonemass", "Dragon", "GoblinKing", "SeekerQueen", "Fader", "FrozenKing", "FrozenKing_p2", "FrozenKing_p3" };

		private static Dictionary<string, int> BuildKnown()
		{
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
			string[] array = new string[8] { "Boar Neck Greyling", "Greydwarf Greydwarf_Elite Greydwarf_Shaman Troll Troll_sleeping Skeleton Skeleton_NoArcher Skeleton_Meadows Skeleton_Meadows_noarcher Ghost Ghost_sleeping Serpent", "Abomination Blob BlobElite Draugr Draugr_Elite Draugr_Ranged Draugr_sleeping Draugr_Elite_sleeping Draugr_Ranged_sleeping Leech Leech_cave Skeleton_Poison Skeleton_Swamps Skeleton_Swamps_noarcher Surtling Wraith Bat_Swamp", "Wolf Hatchling Fenring Fenring_Cultist Bat StoneGolem Ulv Skeleton_Mountains Skeleton_Mountains_noarcher", "Goblin GoblinArcher GoblinBrute GoblinShaman Lox Deathsquito BlobTar", "Seeker SeekerBrute SeekerBrood Gjall Tick", "Asksvin Charred_Archer Charred_Mage Charred_Melee Charred_Melee_Dyrnwyn Charred_Twitcher Morgen Morgen_NonSleeping Volture FallenValkyrie BlobLava BonemawSerpent", "Barka Bjorn Bjorn_sleeping BlobFrost BlobMork BlobMorkMini Elaking ElakingLantern ElakingMole FallenWarrior FrostWisp Frysling Ghost_Void GoblinDeepNorth Goblin_Gem Greydwarf_Frozen Greydwarf_Shaman_Frozen Hive JotunWarrior JotunWarriorDualWield JotunWitch Mistile Skeleton_DeepNorth TentaRoot_wild TheHive TrollFrost Unbjorn Writhan" };
			for (int i = 0; i < array.Length; i++)
			{
				string[] array2 = array[i].Split(' ');
				foreach (string key in array2)
				{
					dictionary[key] = i;
				}
			}
			return dictionary;
		}

		internal Catalogue(Settings settings)
		{
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			HashSet<string> hashSet = new HashSet<string>(from x in settings.ExcludedEnemies.Value.Split(',')
				select x.Trim(), StringComparer.Ordinal);
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
			string[] array = settings.TierOverrides.Value.Split(',');
			for (int num = 0; num < array.Length; num++)
			{
				string[] array2 = array[num].Split('=');
				if (array2.Length == 2 && int.TryParse(array2[1], out var result) && result >= 0 && result < ArenaRules.Biomes.Length)
				{
					dictionary[array2[0].Trim()] = result;
				}
			}
			Dictionary<string, GameObject> dictionary2 = new Dictionary<string, GameObject>(StringComparer.Ordinal);
			foreach (GameObject prefab2 in ZNetScene.instance.m_prefabs)
			{
				if (Object.op_Implicit((Object)(object)prefab2))
				{
					dictionary2[((Object)prefab2).name] = prefab2;
				}
			}
			foreach (string item in Known.Keys.Concat(RosterRules.DvergrPrefabs).Concat(dictionary.Keys).Distinct())
			{
				GameObject prefab = PrefabManager.Instance.GetPrefab(item);
				if (Object.op_Implicit((Object)(object)prefab))
				{
					dictionary2[item] = prefab;
				}
			}
			Dictionary<string, int> dictionary3 = new Dictionary<string, int>(StringComparer.Ordinal);
			SpawnSystemList[] array3 = Resources.FindObjectsOfTypeAll<SpawnSystemList>();
			for (int num = 0; num < array3.Length; num++)
			{
				foreach (SpawnData spawner in array3[num].m_spawners)
				{
					if (!Object.op_Implicit((Object)(object)spawner.m_prefab) || !spawner.m_enabled)
					{
						continue;
					}
					int num2 = BiomeTier(spawner.m_biome);
					if (num2 >= 0)
					{
						dictionary2[((Object)spawner.m_prefab).name] = spawner.m_prefab;
						if (!dictionary3.TryGetValue(((Object)spawner.m_prefab).name, out var value) || num2 < value)
						{
							dictionary3[((Object)spawner.m_prefab).name] = num2;
						}
					}
				}
			}
			foreach (GameObject value3 in dictionary2.Values)
			{
				Character component = value3.GetComponent<Character>();
				if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)value3.GetComponent<MonsterAI>()) || !Object.op_Implicit((Object)(object)value3.GetComponent<ZNetView>()) || component.m_boss || hashSet.Contains(((Object)value3).name) || AlwaysExclude(((Object)value3).name, component))
				{
					continue;
				}
				if (!dictionary.TryGetValue(((Object)value3).name, out var value2) && !RosterRules.TryDvergrTier(((Object)value3).name, ref value2) && !Known.TryGetValue(((Object)value3).name, out value2) && !dictionary3.TryGetValue(((Object)value3).name, out value2))
				{
					if (!(((object)Unsafe.As<Faction, Faction>(ref component.m_faction)/*cast due to .constrained prefix*/).ToString() == "DeepNorth"))
					{
						Plugin.Instance.Warn("No arena tier for hostile prefab " + ((Object)value3).name + "; add an EnemyTierOverrides entry to include it.");
						continue;
					}
					value2 = 7;
				}
				Enemies[((Object)value3).name] = new EnemyDefinition(value3, value2);
			}
			if (Enemies.ContainsKey("DvergerMageFire") && Enemies.ContainsKey("DvergerMageIce") && Enemies.ContainsKey("DvergerMageSupport"))
			{
				Enemies.Remove("DvergerMage");
			}
			HashSet<string> representatives = new HashSet<string>(from entry in RosterRules.Representatives(((IEnumerable<EnemyDefinition>)Enemies.Values).Select((Func<EnemyDefinition, RosterEntry>)((EnemyDefinition enemy) => new RosterEntry(enemy.Prefab, enemy.Name, enemy.Tier))))
				select entry.Prefab, StringComparer.Ordinal);
			array = Enemies.Keys.Where((string name) => !representatives.Contains(name)).ToArray();
			foreach (string key in array)
			{
				Enemies.Remove(key);
			}
			Plugin.Instance.LogInfo("Arena catalogue contains " + Enemies.Count + " distinct non-boss opponents.");
		}

		private static bool AlwaysExclude(string name, Character character)
		{
			string text = ((object)Unsafe.As<Faction, Faction>(ref character.m_faction)/*cast due to .constrained prefix*/).ToString();
			if (!BossNames.Contains(name) && !name.EndsWith("_sleeping", StringComparison.OrdinalIgnoreCase) && !RosterRules.IsMiniboss(name) && !(name == "DvergerTest") && !(character is Player))
			{
				switch (text)
				{
				default:
					if (name.StartsWith("Aspect_", StringComparison.Ordinal) || name.IndexOf("spiritcaller", StringComparison.OrdinalIgnoreCase) >= 0 || name.EndsWith("_Summoned", StringComparison.OrdinalIgnoreCase) || name.EndsWith("_Fader", StringComparison.Ordinal))
					{
						break;
					}
					switch (name)
					{
					default:
						if (!name.EndsWith("_cub", StringComparison.Ordinal) && !name.EndsWith("_Calf", StringComparison.Ordinal) && !name.EndsWith("_calf", StringComparison.Ordinal) && !name.EndsWith("_piggy", StringComparison.Ordinal))
						{
							return name.EndsWith("_hatchling", StringComparison.Ordinal);
						}
						break;
					case "Skeleton_Friendly":
					case "BlobAspect":
					case "Skeleton_aspect":
					case "TentaRoot":
					case "staff_greenroots_tentaroot":
						break;
					}
					break;
				case "Players":
				case "Boss":
				case "PlayerSpawned":
				case "TrainingDummy":
					break;
				}
			}
			return true;
		}

		private static int BiomeTier(Biome biomes)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or mi

BepInEx/plugins/ArenaCombat/ArenaCombat.Core.dll

Decompiled an hour 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 Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ArenaCombat.Core")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ArenaCombat.Core")]
[assembly: AssemblyTitle("ArenaCombat.Core")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.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]
	[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]
	[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 ArenaCombat.Core
{
	public static class ArenaRules
	{
		public static readonly string[] Biomes = new string[8] { "Meadows", "Black Forest", "Swamp", "Mountains", "Plains", "Mistlands", "Ashlands", "Deep North" };

		public static readonly string[] UnlockKeys = new string[8] { "", "defeated_eikthyr", "defeated_gdking", "defeated_bonemass", "defeated_dragon", "defeated_goblinking", "defeated_queen", "defeated_fader" };

		public static int LatestTier(Func<string, bool> hasKey)
		{
			int result = 0;
			for (int i = 1; i < UnlockKeys.Length; i++)
			{
				if (hasKey(UnlockKeys[i]))
				{
					result = i;
				}
			}
			return result;
		}

		public static int Cost(int baseCost, int lootCost, bool loot, int latestTier, int enemyTier, decimal discountPerTier = 0.20m)
		{
			if (baseCost < 0 || lootCost < 0)
			{
				throw new ArgumentOutOfRangeException("baseCost");
			}
			if (enemyTier < 0 || enemyTier > latestTier)
			{
				throw new ArgumentOutOfRangeException("enemyTier");
			}
			if (discountPerTier < 0m || discountPerTier > 1m)
			{
				throw new ArgumentOutOfRangeException("discountPerTier");
			}
			if (!loot)
			{
				return 0;
			}
			decimal num = Math.Max(0m, 1m - (decimal)Math.Max(0, latestTier - enemyTier) * discountPerTier);
			return (int)Math.Ceiling(((decimal)baseCost + (decimal)lootCost) * num);
		}
	}
	public sealed class ReserveBank
	{
		public const long UnitsPerToken = 1000000L;

		public long Units { get; private set; }

		public long UpdatedAtMs { get; private set; }

		public int Reserved { get; private set; }

		public decimal Tokens => (decimal)Units / 1000000m;

		public ReserveBank(long units, long updatedAtMs, int reserved = 0)
		{
			Units = Math.Max(0L, units);
			UpdatedAtMs = updatedAtMs;
			Reserved = Math.Max(0, reserved);
		}

		public void Refill(long nowMs, int capacity, decimal tokensPerMinute)
		{
			if (capacity < 0 || tokensPerMinute < 0m)
			{
				throw new ArgumentOutOfRangeException("capacity");
			}
			long num = Math.Max(0L, (long)capacity - (long)Reserved) * 1000000;
			Units = Math.Min(Units, num);
			if (nowMs < UpdatedAtMs)
			{
				UpdatedAtMs = nowMs;
				return;
			}
			decimal d = (decimal)(nowMs - UpdatedAtMs) * tokensPerMinute * 1000000m / 60000m;
			Units = (long)Math.Min(num, (decimal)Units + Math.Floor(d));
			UpdatedAtMs = nowMs;
		}

		public bool TryReserve(int cost)
		{
			if (cost < 0)
			{
				throw new ArgumentOutOfRangeException("cost");
			}
			if (Reserved != 0 || Units < (long)cost * 1000000L)
			{
				return false;
			}
			Units -= (long)cost * 1000000L;
			Reserved = cost;
			return true;
		}

		public void Commit()
		{
			Reserved = 0;
		}

		public void Refund(int capacity)
		{
			Units = Math.Min((long)Math.Max(0, capacity) * 1000000L, Units + (long)Reserved * 1000000L);
			Reserved = 0;
		}
	}
	public enum EncounterPhase
	{
		Ready,
		Countdown,
		Active
	}
	public sealed class EncounterState
	{
		public EncounterPhase Phase { get; private set; }

		public long DeadlineMs { get; private set; }

		public ReserveBank Bank { get; }

		public EncounterState(ReserveBank bank, EncounterPhase phase = EncounterPhase.Ready, long deadlineMs = 0L)
		{
			Bank = bank;
			Phase = phase;
			DeadlineMs = deadlineMs;
		}

		public bool TryBegin(int cost, long nowMs, int countdownSeconds)
		{
			if (Phase != EncounterPhase.Ready || !Bank.TryReserve(cost))
			{
				return false;
			}
			Phase = EncounterPhase.Countdown;
			checked
			{
				DeadlineMs = nowMs + unchecked((long)Math.Max(0, countdownSeconds)) * 1000L;
				return true;
			}
		}

		public bool CanSpawn(long nowMs)
		{
			if (Phase == EncounterPhase.Countdown)
			{
				return nowMs >= DeadlineMs;
			}
			return false;
		}

		public void SpawnSucceeded()
		{
			if (Phase != EncounterPhase.Countdown)
			{
				throw new InvalidOperationException("No summon is pending.");
			}
			Bank.Commit();
			Phase = EncounterPhase.Active;
			DeadlineMs = 0L;
		}

		public void Cancel(int capacity)
		{
			if (Phase == EncounterPhase.Countdown)
			{
				Bank.Refund(capacity);
				Phase = EncounterPhase.Ready;
				DeadlineMs = 0L;
			}
		}

		public void Finish()
		{
			if (Phase == EncounterPhase.Active)
			{
				Phase = EncounterPhase.Ready;
			}
		}
	}
	public sealed class PresenceGrace
	{
		public long AbsentSinceMs { get; private set; }

		public PresenceGrace(long absentSinceMs = 0L)
		{
			AbsentSinceMs = absentSinceMs;
		}

		public bool Check(bool playerNearby, long nowMs, int graceSeconds)
		{
			if (playerNearby)
			{
				AbsentSinceMs = 0L;
				return false;
			}
			if (AbsentSinceMs == 0L || nowMs < AbsentSinceMs)
			{
				AbsentSinceMs = nowMs;
			}
			return nowMs - AbsentSinceMs >= (long)Math.Max(0, graceSeconds) * 1000L;
		}
	}
	public readonly struct CoinClaim
	{
		public int Charged { get; }

		public long AtMs { get; }

		public CoinClaim(int charged, long atMs)
		{
			Charged = charged;
			AtMs = atMs;
		}
	}
	public sealed class CoinAllowance
	{
		public const long UnitsPerCoin = 1000000L;

		public const long HourMs = 3600000L;

		public const long ReceiptWindowMs = 120000L;

		private readonly Dictionary<string, CoinClaim> claims;

		public long Units { get; private set; }

		public long UpdatedAtMs { get; private set; }

		public long Remainder { get; private set; }

		public int Available => (int)(Units / 1000000);

		public IReadOnlyDictionary<string, CoinClaim> Claims => claims;

		public CoinAllowance(long units, long updatedAtMs, long remainder = 0L, IEnumerable<KeyValuePair<string, CoinClaim>>? savedClaims = null)
		{
			Units = Math.Max(0L, units);
			UpdatedAtMs = updatedAtMs;
			Remainder = Math.Max(0L, Math.Min(3599999L, remainder));
			claims = savedClaims?.ToDictionary<KeyValuePair<string, CoinClaim>, string, CoinClaim>((KeyValuePair<string, CoinClaim> c) => c.Key, (KeyValuePair<string, CoinClaim> c) => c.Value, StringComparer.Ordinal) ?? new Dictionary<string, CoinClaim>(StringComparer.Ordinal);
		}

		public void Refill(long nowMs, int capacity, decimal perHour)
		{
			if (capacity < 0 || perHour < 0m)
			{
				throw new ArgumentOutOfRangeException("capacity");
			}
			long num = (long)capacity * 1000000L;
			Units = Math.Min(Units, num);
			if (nowMs < UpdatedAtMs)
			{
				UpdatedAtMs = nowMs;
				Remainder = 0L;
				return;
			}
			long num2 = (long)Math.Round(perHour * 1000000m, MidpointRounding.AwayFromZero);
			decimal num3 = (decimal)(nowMs - UpdatedAtMs) * (decimal)num2 + (decimal)Remainder;
			decimal num4 = Math.Floor(num3 / 3600000m);
			if (num4 >= (decimal)(num - Units))
			{
				Units = num;
				Remainder = 0L;
			}
			else
			{
				Units += (long)num4;
				Remainder = (long)(num3 % 3600000m);
			}
			UpdatedAtMs = nowMs;
		}

		public int Claim(string source, int requested, long nowMs, int capacity, decimal perHour, bool enabled = true)
		{
			if (string.IsNullOrEmpty(source) || requested < 0)
			{
				throw new ArgumentException("Invalid coin payout.");
			}
			Refill(nowMs, capacity, perHour);
			if (claims.ContainsKey(source))
			{
				return 0;
			}
			int num = (enabled ? Math.Min(requested, Available) : requested);
			int num2 = (enabled ? num : 0);
			Units -= (long)num2 * 1000000L;
			claims[source] = new CoinClaim(num2, nowMs);
			return num;
		}

		public void Undo(string source, int capacity)
		{
			if (claims.TryGetValue(source, out var value))
			{
				Units = Math.Min((long)capacity * 1000000L, Units + (long)value.Charged * 1000000L);
				claims.Remove(source);
			}
		}

		public bool Prune(long nowMs, ISet<string> validSources)
		{
			string[] array = (from c in claims
				where !validSources.Contains(c.Key) && (nowMs < c.Value.AtMs || nowMs - c.Value.AtMs >= 120000)
				select c.Key).ToArray();
			string[] array2 = array;
			foreach (string key in array2)
			{
				claims.Remove(key);
			}
			return array.Length != 0;
		}
	}
	public sealed class DeathPresenceTracker<T> where T : notnull
	{
		private const long ReplicationWindowMs = 5000L;

		private readonly Dictionary<T, long> pending = new Dictionary<T, long>();

		public void Report(T player, long nowMs)
		{
			pending[player] = nowMs;
		}

		public void Clear()
		{
			pending.Clear();
		}

		public bool IsAlive(T player, bool replicatedAlive, long nowMs)
		{
			if (!replicatedAlive)
			{
				pending.Remove(player);
				return false;
			}
			if (!pending.TryGetValue(player, out var value))
			{
				return true;
			}
			if (nowMs >= value && nowMs - value < 5000)
			{
				return false;
			}
			pending.Remove(player);
			return true;
		}

		public void Prune(long nowMs)
		{
			List<T> list = new List<T>();
			foreach (KeyValuePair<T, long> item in pending)
			{
				if (nowMs < item.Value || nowMs - item.Value >= 5000)
				{
					list.Add(item.Key);
				}
			}
			foreach (T item2 in list)
			{
				pending.Remove(item2);
			}
		}
	}
	public static class DifficultyRules
	{
		public const int Minimum = 10;

		public const int Maximum = 30;

		public static bool IsValid(int tenths)
		{
			if (tenths >= 10)
			{
				return tenths <= 30;
			}
			return false;
		}

		public static decimal Strength(int tenths)
		{
			if (!IsValid(tenths))
			{
				throw new ArgumentOutOfRangeException("tenths");
			}
			return (decimal)tenths / 10m;
		}

		public static int LootPercent(int tenths)
		{
			if (!IsValid(tenths))
			{
				throw new ArgumentOutOfRangeException("tenths");
			}
			return tenths * 10 - 50;
		}

		public static int ScaleCount(int count, int percent, double sample)
		{
			if (count < 0 || percent < 0 || percent > 100 || double.IsNaN(sample) || sample < 0.0 || sample > 1.0)
			{
				throw new ArgumentOutOfRangeException("count");
			}
			long num = (long)count * (long)percent;
			checked
			{
				return (int)(unchecked(num / 100) + ((sample < (double)unchecked(num % 100) / 100.0) ? 1 : 0));
			}
		}
	}
	public sealed class RosterEntry
	{
		public string Prefab { get; }

		public string Name { get; }

		public int Tier { get; }

		public RosterEntry(string prefab, string name, int tier)
		{
			Prefab = prefab;
			Name = name;
			Tier = tier;
		}
	}
	public static class RosterRules
	{
		private static readonly Dictionary<string, int> DvergrTiers = new Dictionary<string, int>(StringComparer.Ordinal)
		{
			["Dverger"] = 5,
			["DvergerMage"] = 5,
			["DvergerMageFire"] = 5,
			["DvergerMageIce"] = 5,
			["DvergerMageSupport"] = 5,
			["DvergerAshlands"] = 6,
			["DvergerDeepNorth"] = 7
		};

		public static IEnumerable<string> DvergrPrefabs => DvergrTiers.Keys;

		public static bool TryDvergrTier(string prefab, out int tier)
		{
			return DvergrTiers.TryGetValue(prefab, out tier);
		}

		public static bool IsMiniboss(string prefab)
		{
			if (!(prefab == "Charred_Melee_Dyrnwyn") && prefab.IndexOf("_Hildir", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return prefab.StartsWith("GoblinBruteBros", StringComparison.OrdinalIgnoreCase);
			}
			return true;
		}

		public static string BaseName(string name)
		{
			int num = name.IndexOf('(');
			return ((num < 0) ? name : name.Substring(0, num)).Trim();
		}

		public static string DvergrName(string prefab, string nativeName)
		{
			return prefab switch
			{
				"Dverger" => nativeName + " — Mistlands", 
				"DvergerAshlands" => nativeName + " — Ashlands", 
				"DvergerDeepNorth" => nativeName + " — Deep North", 
				"DvergerMageFire" => nativeName + " — Fire", 
				"DvergerMageIce" => nativeName + " — Frost", 
				"DvergerMageSupport" => nativeName + " — Support", 
				_ => nativeName, 
			};
		}

		public static IReadOnlyList<RosterEntry> Representatives(IEnumerable<RosterEntry> entries)
		{
			return (from @group in entries.GroupBy<RosterEntry, string>((RosterEntry entry) => BaseName(entry.Name), StringComparer.OrdinalIgnoreCase)
				select (from entry in @group
					orderby entry.Tier, (!(entry.Prefab == "Morgen_NonSleeping")) ? ((!entry.Prefab.Contains("_")) ? 1 : 2) : 0
					select entry).ThenBy<RosterEntry, string>((RosterEntry entry) => entry.Prefab, StringComparer.Ordinal).First() into entry
				orderby entry.Tier descending
				select entry).ThenBy<RosterEntry, string>((RosterEntry entry) => entry.Name, StringComparer.Ordinal).ThenBy<RosterEntry, string>((RosterEntry entry) => entry.Prefab, StringComparer.Ordinal).ToList();
		}
	}
}