Decompiled source of MidgardPlus Lodge v0.5.0

plugins/MidgardPlusLodge.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using MidgardPlus.Api;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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 MidgardPlus.Lodge
{
	internal static class ArenaFight
	{
		private sealed class Foe
		{
			public Character Body;

			public string Id = "";

			public string Name = "";

			public bool Head;

			public float Outside;

			public bool Pulled;
		}

		public const string KeyTicket = "MPL_ArenaT";

		public const string KeyWho = "MPL_ArenaW";

		public const string KeyEnd = "MPL_ArenaE";

		public const string KeyHead = "MPL_ArenaH";

		public const string KeyCentre = "MPL_ArenaC";

		private const float Beat = 0.5f;

		private const float FleeSeconds = 10f;

		private const string Fallback = "Skeleton";

		private const float StraySeconds = 20f;

		private const float StrayGap = 6f;

		private const float ExplainEvery = 20f;

		private const float AskAgainEvery = 8f;

		private static readonly List<Foe> Alive = new List<Foe>();

		private static readonly List<KeyValuePair<string, bool>> Reported = new List<KeyValuePair<string, bool>>();

		private static float _explainAt;

		private static float _askAgainAt;

		private static float _openSince;

		private static ArenaPlan _plan;

		private static int _wave = -1;

		private static float _tick;

		private static float _nextWave;

		private static float _outside;

		private static float _endsAt;

		private static bool _wasDead;

		private static bool _sentEnd;

		private static bool _cleared;

		private static bool _warned;

		private static Vector3 _centre;

		public static long Ticket
		{
			get
			{
				if (_plan == null)
				{
					return 0L;
				}
				return _plan.ticket;
			}
		}

		public static bool Active => _plan != null;

		internal static void Reset()
		{
			Dismiss();
			Reported.Clear();
			_plan = null;
			_wave = -1;
			_explainAt = 0f;
			_askAgainAt = 0f;
			_openSince = 0f;
			_outside = 0f;
			_sentEnd = false;
			_cleared = false;
			_warned = false;
			_wasDead = false;
		}

		internal static string Status()
		{
			if (_plan == null)
			{
				return "idle";
			}
			return _plan.kind + " floor " + _plan.floor + ", wave " + (_wave + 1) + " of " + Math.Max(1, _plan.waves.Count) + ", " + Alive.Count + " foes up";
		}

		internal static void OnTold(string op, bool ok, string reason, string extra)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			if ((op == "climb" || op == "seat") && ok)
			{
				if (int.TryParse(extra, out var result) && result > 0)
				{
					QuestNet.Pay(localPlayer, result);
				}
				Begin(ArenaNet.View.bout);
			}
			else if (op == "result")
			{
				End(ok, reason, extra);
			}
			else if (op == "lost" && !ok && _sentEnd)
			{
				Reset();
			}
		}

		private static void Begin(ArenaPlan plan)
		{
			//IL_003d: 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_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_005c: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(plan?.x ?? 0f, plan?.y ?? 0f, plan?.z ?? 0f);
			if (val == Vector3.zero)
			{
				val = Himinbjorg.Where;
			}
			if (plan != null && !((Object)(object)localPlayer == (Object)null) && !(val == Vector3.zero))
			{
				Reset();
				_plan = plan;
				_centre = val;
				_nextWave = Time.time + 4f;
				_endsAt = Time.time + (float)plan.seconds + 30f;
				string text = ((plan.kind == "gauntlet") ? TextApi.T("lodgea_fight_begin", new object[2]
				{
					plan.floor,
					plan.waves.Count
				}) : ((plan.kind == "seat") ? TextApi.T("lodgea_fight_seat", new object[1] { ChampionName(plan) }) : TextApi.T("lodgea_fight_champion", new object[2]
				{
					plan.floor,
					ChampionName(plan)
				})));
				((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}

		internal static string ChampionName(ArenaPlan plan)
		{
			if (plan == null || plan.champion.Length <= 0)
			{
				return TextApi.T("lodgea_champion_beast", Array.Empty<object>());
			}
			return TextApi.T("lodgeq_rival_" + plan.champion, Array.Empty<object>());
		}

		private static void End(bool won, string reason, string extra)
		{
			Player localPlayer = Player.m_localPlayer;
			ArenaPlan plan = _plan;
			Reset();
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			string[] array = (extra ?? "").Split(new char[1] { ':' });
			string text = ((array.Length != 0) ? array[0] : "");
			int result;
			int num = ((array.Length > 1 && int.TryParse(array[1], out result)) ? result : (plan?.floor ?? 0));
			if (won)
			{
				((Character)localPlayer).Message((MessageType)2, (text == "seat") ? TextApi.T("lodgea_won_seat", Array.Empty<object>()) : TextApi.T("lodgea_won", new object[1] { num }), 0, (Sprite)null, false);
				return;
			}
			object obj;
			switch (reason)
			{
			default:
				obj = "time";
				break;
			case "died":
			case "fled":
			case "time":
			case "left":
			case "yield":
			case "off":
				obj = reason;
				break;
			}
			string text2 = (string)obj;
			((Character)localPlayer).Message((MessageType)2, TextApi.T("lodgea_lost_" + text2, new object[1] { num }), 0, (Sprite)null, false);
		}

		private static void Lost(string why)
		{
			if (_plan != null && !_sentEnd)
			{
				_sentEnd = true;
				ArenaNet.Ask("lost", _plan.ticket.ToString(CultureInfo.InvariantCulture) + ":" + why);
			}
		}

		internal static void Yield()
		{
			Lost("yield");
		}

		internal static void Step(float dt)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			if (_plan == null)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			bool flag = ((Character)localPlayer).IsDead();
			if (flag && !_wasDead)
			{
				Lost("died");
			}
			_wasDead = flag;
			_tick += dt;
			if (_tick < 0.5f)
			{
				return;
			}
			float tick = _tick;
			_tick = 0f;
			if (Time.time > _endsAt + 30f)
			{
				Reset();
			}
			else
			{
				if (_sentEnd || flag)
				{
					return;
				}
				if (!(Time.time > _endsAt))
				{
					if (Utils.DistanceXZ(((Component)localPlayer).transform.position, _centre) > 23f)
					{
						if (!_warned)
						{
							_warned = true;
							((Character)localPlayer).Message((MessageType)2, TextApi.T("lodgea_fight_leaving", Array.Empty<object>()), 0, (Sprite)null, false);
						}
						_outside += tick;
						if (_outside >= 10f)
						{
							Lost("fled");
							return;
						}
					}
					else
					{
						_outside = 0f;
						_warned = false;
					}
					try
					{
						Sweep(tick);
						Advance(localPlayer);
						return;
					}
					catch (Exception ex)
					{
						Plugin.Log.LogWarning((object)("A Himinbjörg wave could not be raised: " + ex.Message));
						return;
					}
				}
				Lost("time");
			}
		}

		private static void Advance(Player player)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ZoneSystem.instance == (Object)null || !ZoneSystem.instance.IsZoneLoaded(_centre))
			{
				return;
			}
			if (_plan.kind != "gauntlet")
			{
				if (_wave < 0 && Time.time >= _nextWave)
				{
					_wave = 0;
					Champion(player);
				}
			}
			else if (Alive.Count > 0)
			{
				_cleared = false;
				Explain();
			}
			else if (_wave >= 0 && !_cleared)
			{
				_cleared = true;
				_nextWave = Time.time + 3f;
				_askAgainAt = Time.time + 8f;
				Plugin.Log.LogInfo((object)("Himinbjörg: wave " + (_wave + 1) + " of " + _plan.waves.Count + " on floor " + _plan.floor + " is clear, " + Reported.Count + " fallen told to the keeper so far."));
				if (_wave + 1 >= _plan.waves.Count)
				{
					((Character)player).Message((MessageType)2, TextApi.T("lodgea_fight_counting", Array.Empty<object>()), 0, (Sprite)null, false);
				}
			}
			else if (_wave + 1 >= _plan.waves.Count)
			{
				AskAgain();
			}
			else
			{
				if (Time.time < _nextWave)
				{
					return;
				}
				_wave++;
				_cleared = false;
				_openSince = Time.time;
				_explainAt = Time.time + 20f;
				int num = 0;
				foreach (ArenaSpawn fo in _plan.waves[_wave].foes)
				{
					Character val = Raise(fo.prefab, fo.stars, fo.health, head: false);
					if ((Object)(object)val != (Object)null)
					{
						Track(val, head: false);
					}
					else
					{
						Plugin.Log.LogWarning((object)("Himinbjörg: " + fo.prefab + " for wave " + (_wave + 1) + " could not be raised, so it is counted as fallen."));
						Report("miss:" + _wave + ":" + num, head: false);
					}
					num++;
				}
				((Character)player).Message((MessageType)2, TextApi.T("lodgea_fight_wave", new object[2]
				{
					_wave + 1,
					_plan.waves.Count
				}), 0, (Sprite)null, false);
			}
		}

		private static void Champion(Player player)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			Character val = null;
			if (_plan.champion.Length > 0 && QuestFolk.Ready)
			{
				val = QuestFolk.SpawnRival(_plan.champion, "duel", Around(2f, 4f), "arena", _plan.health, _plan.tier);
				if ((Object)(object)val != (Object)null)
				{
					float maxHealth = val.GetMaxHealth();
					val.SetLevel(Mathf.Clamp(_plan.level, 1, 3));
					val.SetMaxHealth(maxHealth);
					val.SetHealth(maxHealth);
					Mark(val, head: true);
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				val = Raise(_plan.head, 2, _plan.health * 1.5f, head: true);
			}
			_openSince = Time.time;
			_explainAt = Time.time + 20f;
			if ((Object)(object)val != (Object)null)
			{
				Track(val, head: true);
			}
			else
			{
				Plugin.Log.LogWarning((object)("Himinbjörg: the champion for floor " + _plan.floor + " could not be raised."));
			}
			foreach (ArenaSpawn escort in _plan.escorts)
			{
				Character val2 = Raise(escort.prefab, escort.stars, escort.health, head: false);
				if ((Object)(object)val2 != (Object)null)
				{
					Track(val2, head: false);
				}
			}
			((Character)player).Message((MessageType)2, TextApi.T("lodgea_fight_champion_here", new object[1] { ChampionName(_plan) }), 0, (Sprite)null, false);
		}

		private static Vector3 Around(float near, float far)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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_0019: 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_0041: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			Vector2 insideUnitCircle = Random.insideUnitCircle;
			Vector2 val = ((Vector2)(ref insideUnitCircle)).normalized * Random.Range(near, far);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(_centre.x + val.x, _centre.y, _centre.z + val.y);
			float num = default(float);
			if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetSolidHeight(val2, ref num, 1000))
			{
				val2.y = num + 0.5f;
			}
			return val2;
		}

		private static void Mark(Character character, bool head)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			ZNetView component = ((Component)character).GetComponent<ZNetView>();
			ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null);
			Player localPlayer = Player.m_localPlayer;
			if (val != null && !((Object)(object)localPlayer == (Object)null))
			{
				val.Persistent = false;
				val.Set("MPL_ArenaT", _plan.ticket);
				val.Set("MPL_ArenaW", localPlayer.GetPlayerID());
				val.Set("MPL_ArenaE", _plan.deadline);
				val.Set("MPL_ArenaH", head);
				val.Set("MPL_ArenaC", _centre);
				ArenaHooks.Tame(character);
			}
		}

		private static Character Raise(string prefabName, int stars, float health, bool head)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null && !string.IsNullOrEmpty(prefabName)) ? ZNetScene.instance.GetPrefab(prefabName) : null);
			if (((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<Character>() == (Object)null) && (Object)(object)ZNetScene.instance != (Object)null)
			{
				val = ZNetScene.instance.GetPrefab("Skeleton");
			}
			if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<Character>() == (Object)null)
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, Around(4f, 8f), Quaternion.Euler(0f, Random.Range(0f, 360f), 0f));
			Character component = val2.GetComponent<Character>();
			ZNetView component2 = val2.GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || !component2.IsValid())
			{
				Object.Destroy((Object)(object)val2);
				return null;
			}
			Mark(component, head);
			component.SetLevel(Mathf.Clamp(stars + 1, 1, 3));
			if (health > 1.01f)
			{
				component.SetMaxHealth(component.GetMaxHealth() * health);
			}
			component.SetHealth(component.GetMaxHealth());
			BaseAI baseAI = component.GetBaseAI();
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)baseAI != (Object)null && (Object)(object)localPlayer != (Object)null)
			{
				baseAI.SetAggravated(true, (AggravatedReason)0);
				baseAI.Alert();
			}
			return component;
		}

		private static void Dismiss()
		{
			foreach (Foe item in Alive)
			{
				ArenaHooks.Gone(item.Body);
			}
			Alive.Clear();
		}

		private static void Track(Character body, bool head)
		{
			ZNetView component = ((Component)body).GetComponent<ZNetView>();
			ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null);
			Alive.Add(new Foe
			{
				Body = body,
				Id = ((val != null) ? ((object)Unsafe.As<ZDOID, ZDOID>(ref val.m_uid)/*cast due to .constrained prefix*/).ToString() : ""),
				Name = Utils.GetPrefabName(((Component)body).gameObject),
				Head = head
			});
		}

		private static void Report(string id, bool head)
		{
			if (_plan == null || string.IsNullOrEmpty(id))
			{
				return;
			}
			foreach (KeyValuePair<string, bool> item in Reported)
			{
				if (item.Key == id)
				{
					return;
				}
			}
			Reported.Add(new KeyValuePair<string, bool>(id, head));
			ArenaNet.SendFell(_plan.ticket, id, head);
		}

		private static void AskAgain()
		{
			if (_plan == null || _sentEnd || Reported.Count == 0 || Time.time < _askAgainAt)
			{
				return;
			}
			_askAgainAt = Time.time + 8f;
			Plugin.Log.LogInfo((object)("Himinbjörg: the ring is clear on floor " + _plan.floor + " and no result came yet, so the " + Reported.Count + " fallen are told to the keeper again."));
			foreach (KeyValuePair<string, bool> item in Reported)
			{
				ArenaNet.SendFell(_plan.ticket, item.Key, item.Value);
			}
		}

		private static void Sweep(float beat)
		{
			//IL_005d: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			for (int num = Alive.Count - 1; num >= 0; num--)
			{
				Foe foe = Alive[num];
				Character body = foe.Body;
				if ((Object)(object)body == (Object)null || body.IsDead())
				{
					Report(foe.Id, foe.Head);
					Alive.RemoveAt(num);
				}
				else
				{
					float num2 = Utils.DistanceXZ(((Component)body).transform.position, _centre);
					if (num2 <= 17f)
					{
						foe.Outside = 0f;
					}
					else
					{
						foe.Outside += beat;
						if (!(foe.Outside < 20f))
						{
							foe.Outside = 0f;
							ZNetView component = ((Component)body).GetComponent<ZNetView>();
							if (!foe.Pulled && (Object)(object)component != (Object)null && component.IsValid())
							{
								foe.Pulled = true;
								component.ClaimOwnership();
								Vector3 position = Around(2f, 5f);
								((Component)body).transform.position = position;
								Rigidbody component2 = ((Component)body).GetComponent<Rigidbody>();
								if ((Object)(object)component2 != (Object)null)
								{
									component2.position = position;
									component2.linearVelocity = Vector3.zero;
								}
								Plugin.Log.LogInfo((object)("Himinbjörg: " + foe.Name + " stayed " + Mathf.RoundToInt(num2) + " m from the ring centre for " + Mathf.RoundToInt(20f) + " s and was pulled back in."));
							}
							else
							{
								Plugin.Log.LogInfo((object)("Himinbjörg: " + foe.Name + " is " + Mathf.RoundToInt(num2) + " m from the ring centre again after being pulled back once, so it is counted as fallen and sent away."));
								Report(foe.Id, foe.Head);
								ArenaHooks.Gone(body);
								Alive.RemoveAt(num);
							}
						}
					}
				}
			}
		}

		private static void Explain()
		{
			//IL_0082: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			if (_plan == null || Time.time < _explainAt)
			{
				return;
			}
			_explainAt = Time.time + 20f;
			List<string> list = new List<string>();
			foreach (Foe item in Alive)
			{
				Character body = item.Body;
				if (!((Object)(object)body == (Object)null))
				{
					ZNetView component = ((Component)body).GetComponent<ZNetView>();
					bool flag = (Object)(object)component != (Object)null && component.IsValid() && component.IsOwner();
					float num = Utils.DistanceXZ(((Component)body).transform.position, _centre);
					float num2 = ((Component)body).transform.position.y - _centre.y;
					list.Add(item.Name + " " + Mathf.RoundToInt(num) + " m out, " + Mathf.RoundToInt(num2) + " m up, " + Mathf.RoundToInt(body.GetHealth()) + " health" + (flag ? "" : ", run by another game"));
				}
			}
			Plugin.Log.LogInfo((object)("Himinbjörg: wave " + (_wave + 1) + " on floor " + _plan.floor + " is still open after " + Mathf.RoundToInt(Time.time - _openSince) + " s with " + Alive.Count + " foe(s) up: " + string.Join("; ", list.ToArray()) + "."));
		}
	}
	public sealed class ArenaFoe : MonoBehaviour
	{
		private ZNetView _view;

		private LodgeRival _rival;

		private float _next;

		private float _goneAt;

		private bool _told;

		private void Awake()
		{
			_view = ((Component)this).GetComponent<ZNetView>();
			_rival = ((Component)this).GetComponent<LodgeRival>();
			_next = Time.time + Random.Range(0.5f, 1.5f);
		}

		private void Update()
		{
			if (Time.time < _next)
			{
				return;
			}
			_next = Time.time + 1f;
			try
			{
				Look();
			}
			catch (Exception ex)
			{
				_next = Time.time + 5f;
				Plugin.Log.LogWarning((object)("A Himinbjörg foe could not be looked after: " + ex.Message));
			}
		}

		private void Look()
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: 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_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bd: 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_0206: Unknown result type (might be due to invalid IL or missing references)
			ZDO val = (((Object)(object)_view != (Object)null && _view.IsValid()) ? _view.GetZDO() : null);
			if (val == null || !_view.IsOwner())
			{
				return;
			}
			long num = val.GetLong("MPL_ArenaT", 0L);
			if (num == 0L)
			{
				return;
			}
			if (DateTime.UtcNow.Ticks > val.GetLong("MPL_ArenaE", 0L) + ArenaRules.Ticks(30.0))
			{
				ArenaHooks.Gone(((Component)this).GetComponent<Character>());
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && localPlayer.GetPlayerID() == val.GetLong("MPL_ArenaW", 0L) && ArenaFight.Ticket != num)
			{
				ArenaHooks.Gone(((Component)this).GetComponent<Character>());
				return;
			}
			bool flag = false;
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if ((Object)(object)allPlayer != (Object)null && Vector3.Distance(((Component)allPlayer).transform.position, ((Component)this).transform.position) < 60f)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				ArenaHooks.Gone(((Component)this).GetComponent<Character>());
				return;
			}
			Vector3 vec = val.GetVec3("MPL_ArenaC", Vector3.zero);
			if (vec != Vector3.zero && Utils.DistanceXZ(((Component)this).transform.position, vec) > 26f)
			{
				Vector2 val2 = Random.insideUnitCircle * 5f;
				Vector3 val3 = default(Vector3);
				((Vector3)(ref val3))..ctor(vec.x + val2.x, vec.y, vec.z + val2.y);
				float num2 = default(float);
				if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetSolidHeight(val3, ref num2, 1000))
				{
					val3.y = num2 + 0.5f;
				}
				((Component)this).transform.position = val3;
				Rigidbody component = ((Component)this).GetComponent<Rigidbody>();
				if ((Object)(object)component != (Object)null)
				{
					component.position = val3;
					component.linearVelocity = Vector3.zero;
				}
			}
			if ((Object)(object)_rival != (Object)null && _rival.Yielded && !_told)
			{
				_told = true;
				ArenaNet.SendFell(num, ((object)Unsafe.As<ZDOID, ZDOID>(ref val.m_uid)/*cast due to .constrained prefix*/).ToString(), val.GetBool("MPL_ArenaH", false));
				_goneAt = Time.time + 3f;
			}
			if (_goneAt > 0f && Time.time >= _goneAt)
			{
				ArenaHooks.Gone(((Component)this).GetComponent<Character>());
			}
		}
	}
	[HarmonyPatch]
	internal static class ArenaHooks
	{
		internal static long TicketOf(Component thing)
		{
			ZNetView val = (((Object)(object)thing != (Object)null) ? thing.GetComponent<ZNetView>() : null);
			ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null);
			if (val2 == null)
			{
				return 0L;
			}
			return val2.GetLong("MPL_ArenaT", 0L);
		}

		internal static void Tame(Character character)
		{
			if (!((Object)(object)character == (Object)null))
			{
				MonsterAI component = ((Component)character).GetComponent<MonsterAI>();
				if ((Object)(object)component != (Object)null)
				{
					component.m_attackPlayerObjects = false;
				}
				if ((Object)(object)((Component)character).GetComponent<ArenaFoe>() == (Object)null)
				{
					((Component)character).gameObject.AddComponent<ArenaFoe>();
				}
			}
		}

		internal static void Gone(Character character)
		{
			if (!((Object)(object)character == (Object)null) && !((Object)(object)ZNetScene.instance == (Object)null))
			{
				ZNetView component = ((Component)character).GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null && component.IsValid())
				{
					component.ClaimOwnership();
					ZNetScene.instance.Destroy(((Component)character).gameObject);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(MonsterAI), "Awake")]
		private static void Woken(MonsterAI __instance)
		{
			try
			{
				if ((Object)(object)__instance != (Object)null && TicketOf((Component)(object)__instance) != 0L)
				{
					Tame(((Component)__instance).GetComponent<Character>());
				}
			}
			catch (Exception)
			{
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "OnDeath")]
		private static void Fallen(Character __instance)
		{
			try
			{
				if (!((Object)(object)__instance == (Object)null) && !__instance.IsPlayer())
				{
					ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
					ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null);
					long num = ((val != null) ? val.GetLong("MPL_ArenaT", 0L) : 0);
					if (num != 0L)
					{
						ArenaNet.SendFell(num, ((object)Unsafe.As<ZDOID, ZDOID>(ref val.m_uid)/*cast due to .constrained prefix*/).ToString(), val.GetBool("MPL_ArenaH", false));
					}
				}
			}
			catch (Exception)
			{
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "RPC_Damage")]
		private static bool Fair(Character __instance, HitData hit)
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)__instance == (Object)null || hit == null || ((ZDOID)(ref hit.m_attacker)).IsNone() || __instance.IsPlayer())
				{
					return true;
				}
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null);
				if (val == null || val.GetLong("MPL_ArenaT", 0L) == 0L)
				{
					return true;
				}
				ZDO val2 = ((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(hit.m_attacker) : null);
				long num = ((val2 != null) ? val2.GetLong(ZDOVars.s_playerID, 0L) : 0);
				return num == 0L || num == val.GetLong("MPL_ArenaW", 0L);
			}
			catch (Exception)
			{
				return true;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "GetHoverText")]
		private static void KeeperText(Character __instance, ref string __result)
		{
			try
			{
				KeeperBody keeperBody = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent<KeeperBody>() : null);
				if ((Object)(object)keeperBody != (Object)null)
				{
					__result = keeperBody.GetHoverText();
				}
			}
			catch (Exception)
			{
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "GetHoverName")]
		private static void KeeperName(Character __instance, ref string __result)
		{
			try
			{
				KeeperBody keeperBody = (((Object)(object)__instance != (Object)null) ? ((Component)__instance).GetComponent<KeeperBody>() : null);
				if ((Object)(object)keeperBody != (Object)null)
				{
					__result = keeperBody.GetHoverName();
				}
			}
			catch (Exception)
			{
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(EnemyHud), "ShowHud")]
		private static bool KeeperNoBar(Character c)
		{
			try
			{
				return (Object)(object)c == (Object)null || (Object)(object)((Component)c).GetComponent<KeeperBody>() == (Object)null;
			}
			catch (Exception)
			{
				return true;
			}
		}
	}
	public static class ArenaKeeper
	{
		public const string Prefab = "MPL_Vardrun";

		public const string HomeKey = "MPL_ArenaHome";

		public const int LookVersion = 1;

		public const string LookKey = "MPL_ArenaLook";

		private static bool _registered;

		public static bool Ready { get; private set; }

		internal static void Register()
		{
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Expected O, but got Unknown
			//IL_0096: 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_00af: 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)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: 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)
			if (_registered)
			{
				return;
			}
			_registered = true;
			try
			{
				GameObject val = (LodgeArt.StandIns ? null : Body());
				bool flag = (Object)(object)val != (Object)null;
				if ((Object)(object)val == (Object)null)
				{
					val = LodgePrefabs.Empty("MPL_Vardrun");
					if ((Object)(object)val == (Object)null)
					{
						return;
					}
					GameObject val2 = (LodgeArt.HasBundle ? (LodgeArt.Asset<GameObject>("MPL_Model_HringvordrCloak") ?? LodgeArt.Asset<GameObject>("MPL_Model_Hringvordr")) : null);
					if ((Object)(object)val2 != (Object)null)
					{
						LodgePrefabs.Show(val, val2, Vector3.zero, Quaternion.identity, Vector3.one);
					}
					else
					{
						LodgePrefabs.Decor(val, "stone_pillar", Vector3.zero, Quaternion.identity, new Vector3(0.6f, 0.9f, 0.6f));
					}
					CapsuleCollider obj = val.AddComponent<CapsuleCollider>();
					obj.center = new Vector3(0f, 0.95f, 0f);
					obj.radius = 0.45f;
					obj.height = 1.9f;
					val.layer = LayerMask.NameToLayer("piece");
				}
				ZNetView val3 = val.GetComponent<ZNetView>();
				if ((Object)(object)val3 == (Object)null)
				{
					val3 = val.AddComponent<ZNetView>();
				}
				val3.m_persistent = true;
				val.AddComponent<KeeperBody>();
				PrefabManager.Instance.AddPrefab(new CustomPrefab(val, false));
				Ready = true;
				Plugin.Log.LogInfo((object)("The keeper of Himinbjörg stands on " + (flag ? "the player body." : "a plain figure.")));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not make the keeper of Himinbjörg: " + ex));
			}
		}

		private static GameObject Body()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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_00b5: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: 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_00dd: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: 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_0117: Expected O, but got Unknown
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Expected O, but got Unknown
			GameObject val = null;
			try
			{
				val = BodyApi.Build("MPL_Vardrun");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("The player body could not be made for the keeper of Himinbjörg: " + ex.Message));
			}
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Humanoid component = val.GetComponent<Humanoid>();
			if ((Object)(object)component == (Object)null)
			{
				return null;
			}
			((Character)component).m_name = TextApi.Token("lodgea_keeper_name");
			((Character)component).m_faction = (Faction)0;
			((Character)component).m_group = "MPL_Vardrun";
			((Character)component).m_boss = false;
			((Character)component).m_health = 300f;
			((Character)component).m_staggerDamageFactor = 0f;
			((Character)component).m_tolerateFire = true;
			((Character)component).m_damageModifiers = new DamageModifiers
			{
				m_blunt = (DamageModifier)3,
				m_slash = (DamageModifier)3,
				m_pierce = (DamageModifier)3,
				m_chop = (DamageModifier)3,
				m_pickaxe = (DamageModifier)3,
				m_fire = (DamageModifier)3,
				m_frost = (DamageModifier)3,
				m_lightning = (DamageModifier)3,
				m_poison = (DamageModifier)3,
				m_spirit = (DamageModifier)3
			};
			MonsterAI component2 = val.GetComponent<MonsterAI>();
			if ((Object)(object)component2 != (Object)null)
			{
				((BaseAI)component2).m_idleSoundChance = 0f;
				((BaseAI)component2).m_idleSound = new EffectList();
				((BaseAI)component2).m_alertedEffects = new EffectList();
				component2.m_attackPlayerObjects = false;
				((BaseAI)component2).m_aggravatable = false;
				component2.m_enableHuntPlayer = false;
				((BaseAI)component2).m_randomMoveRange = 0f;
				((Behaviour)component2).enabled = false;
			}
			Tameable component3 = val.GetComponent<Tameable>();
			if ((Object)(object)component3 != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component3, true);
			}
			CharacterDrop component4 = val.GetComponent<CharacterDrop>();
			if ((Object)(object)component4 != (Object)null && component4.m_drops != null)
			{
				component4.m_drops.Clear();
			}
			NpcTalk[] componentsInChildren = val.GetComponentsInChildren<NpcTalk>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i], true);
			}
			Rigidbody component5 = val.GetComponent<Rigidbody>();
			if ((Object)(object)component5 != (Object)null)
			{
				component5.mass = 400f;
			}
			return val;
		}
	}
	public sealed class KeeperBody : MonoBehaviour, Hoverable, Interactable
	{
		private ZNetView _view;

		private Character _character;

		private Rigidbody _rigid;

		private float _next;

		private Quaternion _home = Quaternion.Euler(0f, 180f, 0f);

		private void Awake()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			_view = ((Component)this).GetComponent<ZNetView>();
			_character = ((Component)this).GetComponent<Character>();
			_rigid = ((Component)this).GetComponent<Rigidbody>();
			_home = ((Component)this).transform.rotation;
			if ((Object)(object)_character != (Object)null)
			{
				_character.m_name = Glossary.Named("lodgea_keeper_name");
				NpcGuard.Register(_character);
			}
		}

		private void OnDestroy()
		{
			NpcGuard.Unregister(_character);
		}

		private void Update()
		{
			//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_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_00ec: 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_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: 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_011e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_character == (Object)null || Time.time < _next)
			{
				return;
			}
			_next = Time.time + 0.25f;
			ZDO val = (((Object)(object)_view != (Object)null && _view.IsValid()) ? _view.GetZDO() : null);
			if (val == null)
			{
				return;
			}
			try
			{
				Player localPlayer = Player.m_localPlayer;
				bool flag = (Object)(object)localPlayer != (Object)null && TalkMenu.IsOpen && (Object)(object)TalkMenu.Speaker == (Object)(object)((Component)this).transform;
				if (flag && !_view.IsOwner())
				{
					_view.ClaimOwnership();
				}
				if (!_view.IsOwner())
				{
					return;
				}
				Dress(val);
				NpcGuard.Refill(_character);
				Hold(val);
				Quaternion val2 = _home;
				if (flag)
				{
					Vector3 val3 = ((Component)localPlayer).transform.position - ((Component)this).transform.position;
					val3.y = 0f;
					if (((Vector3)(ref val3)).sqrMagnitude > 0.04f)
					{
						val2 = Quaternion.LookRotation(((Vector3)(ref val3)).normalized, Vector3.up);
					}
				}
				if (Quaternion.Angle(((Component)this).transform.rotation, val2) > 1f)
				{
					((Component)this).transform.rotation = val2;
					_character.SetLookDir(((Component)this).transform.forward, 0f);
				}
			}
			catch (Exception ex)
			{
				_next = Time.time + 5f;
				Plugin.Log.LogWarning((object)("The keeper of Himinbjörg could not be looked after: " + ex.Message));
			}
		}

		private void Dress(ZDO zdo)
		{
			//IL_0032: 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)
			if (zdo.GetInt("MPL_ArenaLook", 0) != 1)
			{
				zdo.Set(ZDOVars.s_modelIndex, 1, false);
				zdo.Set(ZDOVars.s_skinColor, new Vector3(0.93f, 0.85f, 0.78f));
				zdo.Set(ZDOVars.s_hairColor, new Vector3(0.86f, 0.86f, 0.84f));
				zdo.Set(ZDOVars.s_hairItem, Hash("Hair20"), false);
				zdo.Set(ZDOVars.s_beardItem, Hash("BeardNone"), false);
				zdo.Set(ZDOVars.s_chestItem, Hash("ArmorPaddedCuirass"), false);
				zdo.Set(ZDOVars.s_legItem, Hash("ArmorPaddedGreaves"), false);
				zdo.Set(ZDOVars.s_helmetItem, 0, false);
				zdo.Set(ZDOVars.s_shoulderItem, Hash("CapeLinen"), false);
				zdo.Set(ZDOVars.s_utilityItem, 0, false);
				zdo.Set(ZDOVars.s_leftItem, 0, false);
				zdo.Set(ZDOVars.s_rightItem, 0, false);
				zdo.Set("MPL_ArenaLook", 1);
			}
		}

		private static int Hash(string item)
		{
			if (string.IsNullOrEmpty(item) || ((Object)(object)ObjectDB.instance != (Object)null && (Object)(object)ObjectDB.instance.GetItemPrefab(item) == (Object)null))
			{
				return 0;
			}
			return StringExtensionMethods.GetStableHashCode(item);
		}

		private void Hold(ZDO zdo)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: 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_004c: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)this).transform.position;
			Vector3 val = zdo.GetVec3("MPL_ArenaHome", Vector3.zero);
			if (val == Vector3.zero)
			{
				val = position;
				zdo.Set("MPL_ArenaHome", val);
			}
			if (Utils.DistanceXZ(position, val) > 0.35f || position.y < val.y - 3f || position.y > val.y + 3f)
			{
				Vector3 position2 = default(Vector3);
				((Vector3)(ref position2))..ctor(val.x, val.y + 0.25f, val.z);
				((Component)this).transform.position = position2;
				if ((Object)(object)_rigid != (Object)null)
				{
					_rigid.position = position2;
					_rigid.linearVelocity = Vector3.zero;
				}
			}
		}

		public string GetHoverText()
		{
			if (!ArenaSettings.On)
			{
				return "";
			}
			return Localization.instance.Localize(GetHoverName() + "\n[<color=yellow><b>$KEY_Use</b></color>] " + TextApi.T("lodgew_master_talk", Array.Empty<object>()));
		}

		public string GetHoverName()
		{
			return Glossary.Named("lodgea_keeper_name");
		}

		public float GetHoverOffset()
		{
			return 0f;
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (hold || (Object)(object)user != (Object)(object)Player.m_localPlayer || !ArenaSettings.On)
			{
				return false;
			}
			ArenaTalk.Open(((Component)this).transform);
			return true;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}
	}
	internal static class ArenaTalk
	{
		private static Transform _speaker;

		private static bool _home;

		internal static void Open(Transform speaker)
		{
			_speaker = speaker;
			ArenaNet.Ask("view");
			Home();
		}

		internal static void OnTold(string op, bool ok, string reason, string extra)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				if (!ok && op != "view" && op != "ack" && op != "result")
				{
					((Character)localPlayer).Message((MessageType)2, Reason(reason), 0, (Sprite)null, false);
				}
				if (op == "join" && ok)
				{
					((Character)localPlayer).Message((MessageType)2, TextApi.T("lodgea_joined", new object[1] { TextApi.T("lodgea_hall_name", Array.Empty<object>()) }), 0, (Sprite)null, false);
				}
				if (Open() && _home)
				{
					Home();
				}
			}
		}

		private static bool Open()
		{
			if ((Object)(object)_speaker != (Object)null && TalkMenu.IsOpen)
			{
				return (Object)(object)TalkMenu.Speaker == (Object)(object)_speaker;
			}
			return false;
		}

		internal static string Reason(string code)
		{
			ArenaView view = ArenaNet.View;
			switch (code ?? "")
			{
			case "wait":
				return TextApi.T("lodgea_reason_wait", new object[1] { Hamskipti.WaitText(Math.Max(60.0, ArenaRules.Seconds(view.nextAt - ArenaNet.Now))) });
			case "coin":
				return TextApi.T("lodgea_reason_coin", new object[1] { view.fee });
			case "busy":
				return TextApi.T("lodgea_reason_busy", new object[1] { (view.busy.Length > 0) ? view.busy : TextApi.T("lodgea_someone", Array.Empty<object>()) });
			case "rank":
			case "slow":
			case "held":
			case "far":
			case "off":
			case "top":
			case "unjoined":
			case "not_top":
				return TextApi.T("lodgea_reason_" + code, Array.Empty<object>());
			default:
				return TextApi.T("lodgea_reason_stale", Array.Empty<object>());
			}
		}

		private static string Title()
		{
			return TextApi.T("lodgea_keeper_title", Array.Empty<object>());
		}

		private static void Say(string text, params KeyValuePair<string, Action>[] choices)
		{
			if (!((Object)(object)_speaker == (Object)null))
			{
				TalkMenu.Say(_speaker, Title(), text, choices);
			}
		}

		internal static string TitleOf(int floor, bool seat)
		{
			if (seat)
			{
				return TextApi.T("lodgea_title_master", Array.Empty<object>());
			}
			int num = ArenaRules.TitleStep(floor);
			if (num <= 0)
			{
				return "";
			}
			return TextApi.T("lodgea_title_" + num, Array.Empty<object>());
		}

		private static void Home()
		{
			_home = true;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)_speaker == (Object)null)
			{
				TalkMenu.Close();
				return;
			}
			ArenaView view = ArenaNet.View;
			List<KeyValuePair<string, Action>> list = new List<KeyValuePair<string, Action>>();
			StringBuilder stringBuilder = new StringBuilder();
			if (!ArenaSettings.On)
			{
				Say(TextApi.T("lodgea_reason_off", Array.Empty<object>()), TalkMenu.Choice("lodgew_menu_close", TalkMenu.Close));
				return;
			}
			if (TrialRoad.Sleeping(localPlayer) && !view.mine && !ArenaFight.Active)
			{
				Gate(localPlayer);
				return;
			}
			if (!ArenaNet.Ready)
			{
				Say(TextApi.T("lodgea_greet_wait_server", Array.Empty<object>()), TalkMenu.Choice("lodgew_menu_close", TalkMenu.Close));
				return;
			}
			if (!view.joined)
			{
				stringBuilder.Append(TextApi.T("lodgea_greet_new", new object[2]
				{
					TextApi.T("lodgea_hall_name", Array.Empty<object>()),
					200
				}));
				if (Lodge.RankOf(localPlayer) < Rank.Sveinn)
				{
					stringBuilder.Append("\n\n").Append(TextApi.T("lodgea_reason_rank", Array.Empty<object>()));
				}
				else
				{
					list.Add(TalkMenu.Choice("lodgea_menu_join", delegate
					{
						ArenaNet.Ask("join");
					}));
				}
			}
			else
			{
				stringBuilder.Append(TextApi.T("lodgea_greet_floor", new object[2] { view.floor, 200 }));
				string text = TitleOf(view.floor, view.seat);
				if (text.Length > 0)
				{
					stringBuilder.Append(' ').Append(TextApi.T("lodgea_greet_title", new object[1] { text }));
				}
				stringBuilder.Append("\n\n");
				double num = ArenaRules.Seconds(view.nextAt - ArenaNet.Now);
				if (view.mine || ArenaFight.Active)
				{
					stringBuilder.Append(TextApi.T("lodgea_greet_fighting", Array.Empty<object>()));
					list.Add(TalkMenu.Choice("lodgea_menu_yield", delegate
					{
						TalkMenu.Close();
						ArenaFight.Yield();
					}));
				}
				else if (view.busy.Length > 0)
				{
					stringBuilder.Append(TextApi.T("lodgea_reason_busy", new object[1] { view.busy }));
				}
				else if (num > 0.0)
				{
					stringBuilder.Append(TextApi.T("lodgea_reason_wait", new object[1] { Hamskipti.WaitText(Math.Max(60.0, num)) }));
				}
				else if (view.floor >= 200)
				{
					stringBuilder.Append(TextApi.T(view.seat ? "lodgea_greet_seat" : "lodgea_greet_top", Array.Empty<object>()));
				}
				else
				{
					stringBuilder.Append(TextApi.T("lodgea_greet_ready", new object[1] { view.floor + 1 }));
				}
				if (!view.mine && !ArenaFight.Active && view.busy.Length == 0 && num <= 0.0)
				{
					if (view.floor < 200)
					{
						int num2 = view.floor + 1;
						list.Add(TalkMenu.Choice("lodgea_menu_climb", delegate
						{
							Confirm("climb");
						}, num2, view.fee));
					}
					else if (!view.seat)
					{
						list.Add(TalkMenu.Choice("lodgea_menu_seat", delegate
						{
							Confirm("seat");
						}, view.fee));
					}
				}
				list.Add(TalkMenu.Choice("lodgea_menu_me", Me));
			}
			if (view.seatName.Length > 0 && !view.seat)
			{
				stringBuilder.Append("\n\n").Append(TextApi.T("lodgea_greet_seat_holder", new object[1] { view.seatName }));
			}
			list.Add(TalkMenu.Choice("lodgea_menu_top", Top));
			list.Add(TalkMenu.Choice("lodgea_menu_lore", Lore));
			list.Add(TalkMenu.Choice("lodgew_menu_close", TalkMenu.Close));
			Say(stringBuilder.ToString(), list.ToArray());
		}

		private static void Gate(Player player)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(TextApi.T("lodgea_gate_sleeping", new object[1] { TextApi.T("lodgea_hall_name", Array.Empty<object>()) }));
			stringBuilder.Append("\n\n").Append(TextApi.T((Lodge.RankOf(player) < Rank.Sveinn) ? "lodgea_gate_unsworn" : "lodgea_gate_unwoken", new object[2]
			{
				TextApi.T("lodgew_hall_name", Array.Empty<object>()),
				TextApi.T("lodgeq_elder_" + TrialRoad.ElderId(player), Array.Empty<object>())
			}));
			stringBuilder.Append("\n\n").Append(TextApi.T("lodgea_gate_offer", Array.Empty<object>()));
			Say(stringBuilder.ToString(), TalkMenu.Choice("lodgea_menu_trials", TrialRoad.Ask), TalkMenu.Choice("lodgea_menu_lore", Lore), TalkMenu.Choice("lodgew_menu_close", TalkMenu.Close));
		}

		private static void Confirm(string op)
		{
			_home = false;
			ArenaView view = ArenaNet.View;
			int num = ((op == "seat") ? 200 : (view.floor + 1));
			string text = ((op == "seat") ? "seat" : ArenaRules.KindOf(num));
			int tier = ArenaRules.LandTier(num, view.tier);
			ArenaPlan arenaPlan = ArenaRules.Plan(num, text, view.tier, 0L, QuestBook.Land(tier), ArenaNet.Champions());
			string text2 = Hamskipti.WaitText(Math.Max(60.0, (double)view.wait * 60.0));
			string text3 = ((text == "gauntlet") ? TextApi.T("lodgea_confirm_gauntlet", new object[6]
			{
				num,
				arenaPlan.waves.Count,
				ArenaRules.PerWave(num),
				QuestText.Land(tier),
				view.fee,
				text2
			}) : ((!(text == "champion")) ? TextApi.T("lodgea_confirm_seat", new object[2] { view.fee, text2 }) : TextApi.T("lodgea_confirm_champion", new object[5]
			{
				num,
				ArenaFight.ChampionName(arenaPlan),
				arenaPlan.escorts.Count,
				view.fee,
				text2
			})));
			text3 = text3 + "\n\n" + TextApi.T("lodgea_confirm_rules", Array.Empty<object>());
			Say(text3, TalkMenu.Choice("lodgea_menu_go", delegate
			{
				TalkMenu.Close();
				ArenaNet.Ask(op);
			}), TalkMenu.Choice("lodgew_menu_back", Home));
		}

		private static void Me()
		{
			_home = false;
			ArenaView view = ArenaNet.View;
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(TextApi.T("lodgea_me", new object[4] { view.floor, 200, view.wins, view.losses })).Append('\n');
			string text = TitleOf(view.floor, view.seat);
			if (text.Length > 0)
			{
				stringBuilder.Append(TextApi.T("lodgea_greet_title", new object[1] { text })).Append('\n');
			}
			double num = ArenaRules.Seconds(view.nextAt - ArenaNet.Now);
			stringBuilder.Append((num > 0.0) ? TextApi.T("lodgea_reason_wait", new object[1] { Hamskipti.WaitText(Math.Max(60.0, num)) }) : TextApi.T("lodgea_me_ready", Array.Empty<object>())).Append("\n\n");
			stringBuilder.Append(TextApi.T("lodgea_me_gifts", Array.Empty<object>())).Append('\n');
			for (int i = 0; i < ArenaRules.Milestones.Length; i++)
			{
				int num2 = ArenaRules.Milestones[i];
				stringBuilder.Append((view.floor >= num2) ? "[x] " : "[  ] ").Append(TextApi.T("lodgea_me_gift", new object[5]
				{
					num2,
					TextApi.T("lodgea_title_" + num2, Array.Empty<object>()),
					ArenaRules.MilestoneRunes[i],
					QuestText.Item("MP_Runestone"),
					TextApi.T("lodgea_perk_" + num2, Array.Empty<object>())
				})).Append('\n');
			}
			stringBuilder.Append(view.seat ? "[x] " : "[  ] ").Append(TextApi.T("lodgea_perk_master", Array.Empty<object>()));
			Say(stringBuilder.ToString(), TalkMenu.Choice("lodgew_menu_back", Home));
		}

		private static void Top()
		{
			_home = false;
			ArenaView view = ArenaNet.View;
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(TextApi.T("lodgea_top_head", Array.Empty<object>())).Append("\n\n");
			if (view.top.Count == 0)
			{
				stringBuilder.Append(TextApi.T("lodgea_top_none", Array.Empty<object>()));
			}
			for (int i = 0; i < view.top.Count; i++)
			{
				ArenaRow arenaRow = view.top[i];
				string value = (arenaRow.seat ? TextApi.T("lodgea_top_seat", new object[3]
				{
					i + 1,
					arenaRow.name,
					arenaRow.floor
				}) : TextApi.T("lodgea_top_row", new object[4]
				{
					i + 1,
					arenaRow.name,
					arenaRow.floor,
					arenaRow.wins
				}));
				string text = TitleOf(arenaRow.floor, arenaRow.seat);
				stringBuilder.Append(value);
				if (text.Length > 0 && !arenaRow.seat)
				{
					stringBuilder.Append(" (").Append(text).Append(')');
				}
				stringBuilder.Append('\n');
			}
			Say(stringBuilder.ToString(), TalkMenu.Choice("lodgew_menu_back", Home));
		}

		private static void Lore()
		{
			_home = false;
			if (LodgeSettings.TalesOn)
			{
				Say(TextApi.T("lodgea_lore", Array.Empty<object>()), TalkMenu.Choice("lodgea_menu_lore_more", Rules), TalkMenu.Choice("lodgea_menu_tale_founding", TaleFounding), TalkMenu.Choice("lodgea_menu_tale_meaning", TaleMeaning), TalkMenu.Choice("lodgea_menu_tale_keeper", TaleKeeper), TalkMenu.Choice("lodgew_menu_back", Home));
			}
			else
			{
				Say(TextApi.T("lodgea_lore", Array.Empty<object>()), TalkMenu.Choice("lodgea_menu_lore_more", Rules), TalkMenu.Choice("lodgew_menu_back", Home));
			}
		}

		private static void TaleFounding()
		{
			_home = false;
			Say(TextApi.T("lodgea_tale_founding", Array.Empty<object>()), TalkMenu.Choice("lodgea_menu_tale_meaning", TaleMeaning), TalkMenu.Choice("lodgea_menu_tale_keeper", TaleKeeper), TalkMenu.Choice("lodgea_menu_lore", Lore), TalkMenu.Choice("lodgew_menu_back", Home));
		}

		private static void TaleMeaning()
		{
			_home = false;
			Say(TextApi.T("lodgea_tale_meaning", Array.Empty<object>()), TalkMenu.Choice("lodgea_menu_tale_founding", TaleFounding), TalkMenu.Choice("lodgea_menu_tale_keeper", TaleKeeper), TalkMenu.Choice("lodgea_menu_lore", Lore), TalkMenu.Choice("lodgew_menu_back", Home));
		}

		private static void TaleKeeper()
		{
			_home = false;
			Say(TextApi.T("lodgea_tale_keeper", Array.Empty<object>()), TalkMenu.Choice("lodgea_menu_tale_founding", TaleFounding), TalkMenu.Choice("lodgea_menu_tale_meaning", TaleMeaning), TalkMenu.Choice("lodgea_menu_lore", Lore), TalkMenu.Choice("lodgew_menu_back", Home));
		}

		private static void Rules()
		{
			_home = false;
			Say(TextApi.T("lodgea_lore_rules", new object[2] { 200, 10 }), TalkMenu.Choice("lodgew_menu_back", Home));
		}
	}
	public static class ArenaSettings
	{
		public const string Section = "Lodge - Himinbjorg";

		public static Synced<bool> Enabled;

		public static Synced<int> EntryFee;

		public static Synced<int> WaitMinutes;

		public static Synced<float> Reward;

		private static bool _bound;

		public static bool On
		{
			get
			{
				if (Lodge.On && Enabled != null)
				{
					return Enabled.Value;
				}
				return false;
			}
		}

		public static int Fee
		{
			get
			{
				if (EntryFee == null)
				{
					return 25;
				}
				return Mathf.Clamp(EntryFee.Value, 0, 1000);
			}
		}

		public static int Wait
		{
			get
			{
				if (WaitMinutes == null)
				{
					return 10;
				}
				return Mathf.Clamp(WaitMinutes.Value, 0, 240);
			}
		}

		public static float Strength
		{
			get
			{
				if (Reward == null)
				{
					return 1f;
				}
				return Mathf.Clamp(Reward.Value, 0f, 5f);
			}
		}

		internal static void Bind(BaseUnityPlugin plugin)
		{
			if (!_bound)
			{
				_bound = true;
				ConfigFile config = plugin.Config;
				Enabled = SettingsApi.Bind<bool>(config, "Lodge - Himinbjorg", "Himinbjorg", false, "Raises Himinbjörg, the arena tower at the edge of the sky, once in the world while The Lodge is on. Hunters climb its 200 floors by winning fights for coin, Virðing and Megin. Off means no tower is placed, its keeper stays silent and nothing saved is lost.");
				LodgeSettings.Add("Lodge - Himinbjorg", "Himinbjorg", "arena_on");
				EntryFee = SettingsApi.Range<int>(config, "Lodge - Himinbjorg", "Himinbjorg entry fee", 25, 0, 1000, "Coins a hunter pays the keeper for each fight in the ring. Floor 50 halves it, and the holder of the high seat pays nothing.");
				LodgeSettings.Add("Lodge - Himinbjorg", "Himinbjorg entry fee", "arena_fee");
				WaitMinutes = SettingsApi.Range<int>(config, "Lodge - Himinbjorg", "Himinbjorg wait minutes", 2, 0, 240, "Real minutes a hunter waits after a fight, won or lost, before the next one. Floor 100 halves it.");
				LodgeSettings.Add("Lodge - Himinbjorg", "Himinbjorg wait minutes", "arena_wait");
				Reward = SettingsApi.Range<float>(config, "Lodge - Himinbjorg", "Himinbjorg reward strength", 1f, 0f, 5f, "Scales the coin and Megin paid for each floor won. Virðing and the milestone gifts are never scaled.");
				LodgeSettings.Add("Lodge - Himinbjorg", "Himinbjorg reward strength", "arena_reward");
			}
		}
	}
	internal sealed class ArenaModule : ILodgeModule
	{
		private static Harmony _harmony;

		public int Order => 40;

		public void Init(BaseUnityPlugin plugin)
		{
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Expected O, but got Unknown
			ArenaSettings.Bind(plugin);
			if (Lodge.Asleep)
			{
				return;
			}
			PrefabManager.OnVanillaPrefabsAvailable += ArenaKeeper.Register;
			ZoneManager.OnVanillaLocationsAvailable += Himinbjorg.Register;
			SettingsApi.Changed += Himinbjorg.Unsettle;
			Plugin.Frame += Himinbjorg.Step;
			Plugin.Frame += ArenaNet.Step;
			Plugin.Frame += ArenaFight.Step;
			Plugin.Frame += TrialRoad.Step;
			ArenaNet.Told += ArenaFight.OnTold;
			ArenaNet.Told += ArenaTalk.OnTold;
			ArenaNet.Told += TrialRoad.OnTold;
			try
			{
				_harmony = new Harmony("midgardplus.lodge.arena");
				_harmony.PatchAll(typeof(ArenaHooks));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Some Himinbjorg hooks are off in this session: " + ex.Message));
			}
			try
			{
				CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new Himinbjorg.ArenaCommand());
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogWarning((object)("The mpl_arena console command could not be added: " + ex2.Message));
			}
		}

		public void WorldStart()
		{
			ArenaNet.Register();
			Himinbjorg.Start();
		}

		public void WorldEnd()
		{
			ArenaFight.Reset();
			TrialRoad.Reset();
			ArenaNet.Leave();
			Himinbjorg.End();
		}
	}
	public static class ArenaNet
	{
		public const string RpcAsk = "MPL_ArenaAsk";

		public const string RpcTell = "MPL_ArenaTell";

		public const string RpcFell = "MPL_ArenaFell";

		public const string ClaimKey = "MPL_Arena";

		public const string OpView = "view";

		public const string OpJoin = "join";

		public const string OpYield = "yield";

		public const string OpLost = "lost";

		public const string OpAck = "ack";

		public const string OpResult = "result";

		public const string OpTrials = "trials";

		private const string FileName = "arena.json";

		private const int TextLimit = 64;

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

		private static readonly Dictionary<long, long> SentAt = new Dictionary<long, long>();

		private static ZRoutedRpc _registered;

		private static ArenaBook _book;

		private static long _bookWorld;

		private static string _written;

		private static ArenaBout _bout;

		private static float _tick;

		private static ArenaView _view = new ArenaView();

		private static ArenaClaim _claim;

		private static long _skew;

		internal static int DevTier;

		public static ArenaView View => _view;

		public static bool Ready { get; private set; }

		public static long Now => DateTime.UtcNow.Ticks + _skew;

		public static event Action<string, bool, string, string> Told;

		internal static void Register()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null && instance != _registered)
			{
				_registered = instance;
				Reset();
				instance.Register<ZPackage>("MPL_ArenaAsk", (Action<long, ZPackage>)OnAsk);
				instance.Register<ZPackage>("MPL_ArenaTell", (Action<long, ZPackage>)OnTell);
				instance.Register<ZPackage>("MPL_ArenaFell", (Action<long, ZPackage>)OnFell);
			}
		}

		internal static void Reset()
		{
			Asked.Clear();
			SentAt.Clear();
			_book = null;
			_bookWorld = 0L;
			_written = null;
			_bout = null;
			_view = new ArenaView();
			_claim = null;
			_skew = 0L;
			Ready = false;
		}

		internal static void Leave()
		{
			if (_bout != null && Server())
			{
				Resolve(won: false, "left");
			}
			Reset();
			DevTier = 0;
			_registered = null;
		}

		private static bool Online()
		{
			if ((Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null)
			{
				return false;
			}
			Register();
			return true;
		}

		private static bool Server()
		{
			if ((Object)(object)ZNet.instance != (Object)null)
			{
				return ZNet.instance.IsServer();
			}
			return false;
		}

		private static long ServerId()
		{
			if (ZNet.instance.IsServer())
			{
				return ZNet.GetUID();
			}
			return ZNet.instance.GetServerPeer()?.m_uid ?? 0;
		}

		public static void Ask(string op, string arg = "")
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && Online())
			{
				ZPackage val = new ZPackage();
				val.Write(op ?? "");
				val.Write(arg ?? "");
				val.Write(localPlayer.GetPlayerID());
				val.Write(QuestNet.Coins(localPlayer));
				long num = ServerId();
				if (num != 0L)
				{
					RpcTally.Count("MPL_ArenaAsk");
					ZRoutedRpc.instance.InvokeRoutedRPC(num, "MPL_ArenaAsk", new object[1] { val });
				}
			}
		}

		public static void SendFell(long ticket, string id, bool head)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			if (ZRoutedRpc.instance != null && !((Object)(object)ZNet.instance == (Object)null) && ticket != 0L)
			{
				ZPackage val = new ZPackage();
				val.Write(ticket);
				val.Write(id ?? "");
				val.Write(head);
				long num = ServerId();
				if (num != 0L)
				{
					RpcTally.Count("MPL_ArenaFell");
					ZRoutedRpc.instance.InvokeRoutedRPC(num, "MPL_ArenaFell", new object[1] { val });
				}
			}
		}

		internal static List<string> Champions()
		{
			List<string> list = new List<string>();
			if (!QuestBook.Ready)
			{
				return list;
			}
			foreach (RivalInfo rival in QuestBook.Rivals)
			{
				if (rival != null && rival.candidate)
				{
					list.Add(rival.id);
				}
			}
			return list;
		}

		internal static int WorldTier()
		{
			if (DevTier > 0)
			{
				return Mathf.Clamp(DevTier, 1, 7);
			}
			return QuestRules.WorldTier((string key) => (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey(key));
		}

		private static string BookPath()
		{
			return Path.Combine(Ledger.Folder(), "arena.json");
		}

		private static ArenaBook Book()
		{
			long num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldUID() : 0);
			if (_book != null && _bookWorld == num)
			{
				return _book;
			}
			ArenaBook arenaBook = null;
			try
			{
				arenaBook = SafeFile.Read(BookPath(), Wire.FromJson<ArenaBook>, delegate(string line)
				{
					Plugin.Log.LogWarning((object)("Himinbjörg ledger: " + line));
				}, out var text);
				if (arenaBook != null)
				{
					_written = text;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not read the Himinbjörg ledger: " + ex.Message));
			}
			arenaBook = arenaBook ?? new ArenaBook();
			ArenaRules.Mend(arenaBook);
			_book = arenaBook;
			_bookWorld = num;
			return _book;
		}

		private static void Save()
		{
			if (_book == null)
			{
				return;
			}
			try
			{
				string text = Wire.ToJson(_book, pretty: true);
				if (!(text == _written))
				{
					SafeFile.Write(BookPath(), text);
					_written = text;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not write the Himinbjörg ledger: " + ex.Message));
			}
		}

		private static long TruePlayer(long sender, long claimed, out string name, out Vector3 at)
		{
			//IL_0008: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			name = "";
			at = Vector3.zero;
			if (sender == ZNet.GetUID())
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null)
				{
					name = localPlayer.GetPlayerName();
					at = ((Component)localPlayer).transform.position;
					return localPlayer.GetPlayerID();
				}
				return claimed;
			}
			ZNetPeer peer = ZNet.instance.GetPeer(sender);
			if (peer == null)
			{
				return 0L;
			}
			name = peer.m_playerName ?? "";
			at = peer.m_refPos;
			ZDO val = ((ZDOMan.instance != null && !((ZDOID)(ref peer.m_characterID)).IsNone()) ? ZDOMan.instance.GetZDO(peer.m_characterID) : null);
			if (val != null)
			{
				at = val.GetPosition();
			}
			long num = ((val != null) ? val.GetLong(ZDOVars.s_playerID, 0L) : 0);
			if (num == 0L)
			{
				return claimed;
			}
			return num;
		}

		private static ArenaContext Context(long player, Vector3 at, int coins)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			LedgerRecord ledgerRecord = LodgeNet.Held(player) ?? Ledger.Load(player);
			return new ArenaContext
			{
				On = (ArenaSettings.On && Himinbjorg.Registered),
				Rank = ((ledgerRecord != null) ? Mathf.Clamp(ledgerRecord.rank, 0, 4) : 0),
				Coins = Math.Max(0, coins),
				Near = Himinbjorg.Near(at, 70f),
				Now = DateTime.UtcNow.Ticks,
				WorldTier = WorldTier(),
				Fee = ArenaSettings.Fee,
				WaitMinutes = ArenaSettings.Wait,
				Strength = ArenaSettings.Strength,
				Quests = QuestSettings.On,
				Busy = ((_bout != null) ? _bout.Name : "")
			};
		}

		private static void OnAsk(long sender, ZPackage package)
		{
			//IL_041d: 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_039f: Unknown result type (might be due to invalid IL or missing references)
			if (!Server())
			{
				return;
			}
			string text;
			string text2;
			long claimed;
			int coins;
			try
			{
				text = package.ReadString() ?? "";
				text2 = package.ReadString() ?? "";
				claimed = package.ReadLong();
				coins = package.ReadInt();
			}
			catch (Exception)
			{
				return;
			}
			if (text.Length > 16 || text2.Length > 64)
			{
				return;
			}
			float unscaledTime = Time.unscaledTime;
			if (text != "ack" && text != "lost" && Asked.TryGetValue(sender, out var value) && unscaledTime - value < 0.2f)
			{
				Tell(sender, text, ok: false, "slow", null, "");
				return;
			}
			Asked[sender] = unscaledTime;
			string name;
			Vector3 at;
			long num = TruePlayer(sender, claimed, out name, out at);
			if (num == 0L)
			{
				return;
			}
			ArenaContext arenaContext = Context(num, at, coins);
			ArenaBook book = Book();
			ArenaRecord arenaRecord = ArenaRules.Find(book, num);
			ArenaRules.Cap(arenaRecord, arenaContext);
			if (arenaRecord != null && name.Length > 0)
			{
				arenaRecord.name = name;
			}
			string text3 = "";
			string extra = "";
			try
			{
				switch (text)
				{
				case "join":
					if (!arenaContext.On)
					{
						text3 = "off";
					}
					else if (!ArenaRules.Qualifies(arenaContext.Rank))
					{
						text3 = "rank";
					}
					else if (arenaRecord == null)
					{
						arenaRecord = ArenaRules.Join(book, num, name, arenaContext.Now);
						Plugin.Log.LogInfo((object)("Himinbjörg: " + name + " (" + num.ToString(CultureInfo.InvariantCulture) + ") put a name on the tower."));
					}
					break;
				case "seat":
				case "climb":
					text3 = Begin(sender, num, name, arenaRecord, arenaContext, text, out extra);
					break;
				case "lost":
				case "yield":
					if (_bout != null && _bout.Player == num && (text2.Length == 0 || text2.StartsWith(_bout.Plan.ticket.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal)))
					{
						int num2 = text2.IndexOf(':');
						string text4 = ((text == "yield") ? "yield" : ((num2 > 0) ? text2.Substring(num2 + 1) : "died"));
						object why;
						switch (text4)
						{
						default:
							why = "died";
							break;
						case "fled":
						case "yield":
						case "time":
							why = text4;
							break;
						}
						Resolve(won: false, (string)why);
						return;
					}
					text3 = "stale";
					break;
				case "trials":
					text3 = Trials(sender, num, name, arenaContext, at, out extra);
					break;
				case "ack":
				{
					if (long.TryParse(text2, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
					{
						ArenaRules.Ack(arenaRecord, result);
					}
					break;
				}
				default:
					text3 = "stale";
					break;
				case "view":
					break;
				}
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogError((object)("A Himinbjörg step failed (" + text + "): " + ex2));
				text3 = "stale";
			}
			Save();
			Tell(sender, text, text3.Length == 0, text3, ArenaRules.View(book, arenaRecord, Context(num, at, coins), _bout), extra);
		}

		private static string Begin(long sender, long player, string name, ArenaRecord record, ArenaContext ctx, string op, out string extra)
		{
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			extra = "";
			if (_bout != null && (ArenaRules.Expired(_bout.Plan, ctx.Now) || (_bout.Peer != ZNet.GetUID() && ZNet.instance.GetPeer(_bout.Peer) == null)))
			{
				Resolve(won: false, ArenaRules.Expired(_bout.Plan, ctx.Now) ? "time" : "left");
				ctx.Busy = "";
			}
			int fee;
			string text = ArenaRules.CanBegin(record, ctx, op, Book().seat, out fee);
			if (text.Length > 0)
			{
				return text;
			}
			int floor = ((op == "seat") ? 200 : ArenaRules.Next(record));
			string text2 = ((op == "seat") ? "seat" : ArenaRules.KindOf(floor));
			long ticket = NewTicket();
			LandInfo land = QuestBook.Land(ArenaRules.LandTier(floor, ctx.WorldTier));
			ArenaPlan arenaPlan = ArenaRules.Plan(floor, text2, ctx.WorldTier, ticket, land, Champions());
			ArenaRules.Start(arenaPlan, ctx.Now);
			arenaPlan.x = Himinbjorg.Where.x;
			arenaPlan.y = Himinbjorg.Where.y;
			arenaPlan.z = Himinbjorg.Where.z;
			_bout = new ArenaBout
			{
				Plan = arenaPlan,
				Player = player,
				Peer = sender,
				Name = name
			};
			extra = fee.ToString(CultureInfo.InvariantCulture);
			Plugin.Log.LogInfo((object)("Himinbjörg: " + name + " (" + player.ToString(CultureInfo.InvariantCulture) + ") stepped into the ring for " + text2 + " floor " + floor + ", " + fee + " coin paid, " + arenaPlan.need + " to fell."));
			return "";
		}

		private static string Trials(long sender, long player, string name, ArenaContext ctx, Vector3 at, out string extra)
		{
			//IL_002f: 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)
			extra = "";
			SentAt.TryGetValue(player, out var value);
			bool hallKnown = Lodge.On && Ydalir.Registered && Ydalir.Known;
			string text = ArenaRules.SendOff(ctx, hallKnown, Character.InInterior(at), Dead(sender), value);
			if (text.Length > 0)
			{
				return text;
			}
			SentAt[player] = ctx.Now;
			extra = Pack(Ydalir.Where);
			Plugin.Log.LogInfo((object)("Himinbjörg: " + name + " (" + player.ToString(CultureInfo.InvariantCulture) + "), whose Megin sleeps, was sent from the tower to the trials at Ýdalir."));
			return "";
		}

		private static bool Dead(long sender)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (sender == ZNet.GetUID())
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null))
				{
					return ((Character)localPlayer).IsDead();
				}
				return true;
			}
			ZNetPeer peer = ZNet.instance.GetPeer(sender);
			if (peer == null || ((ZDOID)(ref peer.m_characterID)).IsNone() || ZDOMan.instance == null)
			{
				return true;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(peer.m_characterID);
			if (zDO != null)
			{
				return zDO.GetBool(ZDOVars.s_dead, false);
			}
			return true;
		}

		internal static string Pack(Vector3 at)
		{
			return at.x.ToString("0.##", CultureInfo.InvariantCulture) + "|" + at.y.ToString("0.##", CultureInfo.InvariantCulture) + "|" + at.z.ToString("0.##", CultureInfo.InvariantCulture);
		}

		internal static bool Unpack(string text, out Vector3 at)
		{
			//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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			at = Vector3.zero;
			string[] array = (text ?? "").Split(new char[1] { '|' });
			if (array.Length != 3)
			{
				return false;
			}
			if (!float.TryParse(array[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
			{
				return false;
			}
			if (float.IsNaN(result) || float.IsNaN(result2) || float.IsNaN(result3) || Mathf.Abs(result) > 20000f || Mathf.Abs(result3) > 20000f || Mathf.Abs(result2) > 3000f)
			{
				return false;
			}
			at = new Vector3(result, result2, result3);
			return at != Vector3.zero;
		}

		private static long NewTicket()
		{
			long num = BitConverter.ToInt64(Guid.NewGuid().ToByteArray(), 0) & 0x7FFFFFFFFFFFFFFFL;
			if (num != 0L)
			{
				return num;
			}
			return 1L;
		}

		private static void Resolve(bool won, string why)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			ArenaBout bout = _bout;
			_bout = null;
			if (bout == null)
			{
				return;
			}
			ArenaBook book = Book();
			ArenaRecord arenaRecord = ArenaRules.Find(book, bout.Player);
			ArenaContext arenaContext = Context(bout.Player, Vector3.zero, 0);
			arenaContext.Busy = "";
			string extra = bout.Plan.kind + ":" + bout.Plan.floor.ToString(CultureInfo.InvariantCulture);
			if (arenaRecord != null)
			{
				if (won)
				{
					Payout payout = ArenaRules.Win(book, arenaRecord, bout.Plan, arenaContext);
					if (payout.standing > 0)
					{
						payout.standing = QuestNet.Honour(bout.Player, payout.standing);
					}
					Plugin.Log.LogInfo((object)("Himinbjörg: " + arenaRecord.name + " won " + bout.Plan.kind + " floor " + bout.Plan.floor + " and is paid " + payout.coins + " coin, " + payout.standing + " Virðing, " + Mathf.RoundToInt(payout.megin * 100f) + "% of a Megin level" + ((payout.count > 0) ? (", " + payout.count + " " + payout.item) : "") + "."));
				}
				else
				{
					ArenaRules.Lose(arenaRecord, arenaContext);
					Plugin.Log.LogInfo((object)("Himinbjörg: " + arenaRecord.name + " lost " + bout.Plan.kind + " floor " + bout.Plan.floor + " (" + why + ")."));
				}
			}
			Save();
			if (ZRoutedRpc.instance != null && (bout.Peer == ZNet.GetUID() || ZNet.instance.GetPeer(bout.Peer) != null))
			{
				Tell(bout.Peer, "result", won, won ? "won" : why, ArenaRules.View(book, arenaRecord, arenaContext, null), extra);
			}
		}

		internal static void Step(float dt)
		{
			_tick += dt;
			if (_tick < 1f)
			{
				return;
			}
			_tick = 0f;
			if (!Server() || _bout == null)
			{
				return;
			}
			long ticks = DateTime.UtcNow.Ticks;
			try
			{
				if (ArenaRules.Won(_bout, ticks))
				{
					Resolve(won: true, "won");
				}
				else if (ArenaRules.Expired(_bout.Plan, ticks))
				{
					Resolve(won: false, "time");
				}
				else if (_bout.Peer != ZNet.GetUID() && ZNet.instance.GetPeer(_bout.Peer) == null)
				{
					Resolve(won: false, "left");
				}
				else if (!ArenaSettings.On)
				{
					Resolve(won: false, "off");
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("A Himinbjörg bout could not be judged: " + ex.Message));
				_bout = null;
			}
		}

		private static void OnFell(long sender, ZPackage package)
		{
			if (!Server() || _bout == null)
			{
				return;
			}
			long num;
			string text;
			bool flag;
			try
			{
				num = package.ReadLong();
				text = package.ReadString() ?? "";
				flag = package.ReadBool();
			}
			catch (Exception)
			{
				return;
			}
			if (num != _bout.Plan.ticket || text.Length > 64)
			{
				if (num != _bout.Plan.ticket)
				{
					Plugin.Log.LogInfo((object)("Himinbjörg: a fallen foe from an older fight was not counted for " + _bout.Name + "."));
				}
				return;
			}
			long ticks = DateTime.UtcNow.Ticks;
			bool flag2 = !_bout.Counted.Contains(text);
			if (!ArenaRules.Count(_bout, text, flag, ticks))
			{
				if (flag2)
				{
					Plugin.Log.LogInfo((object)("Himinbjörg: a fallen foe was not counted for " + _bout.Name + " on floor " + _bout.Plan.floor + " (" + ((_bout.Plan.kind != "gauntlet" && !flag) ? "not the champion" : "outside the fight's time") + ")."));
				}
				return;
			}
			bool flag3 = ArenaRules.Won(_bout, ticks);
			Plugin.Log.LogInfo((object)("Himinbjörg: " + _bout.Name + " felled " + _bout.Kills + " of " + _bout.Plan.need + " on floor " + _bout.Plan.floor + ((flag3 || _bout.Kills < _bout.Plan.need) ? "." : ", the fight ends once its shortest time has passed.")));
			if (flag3)
			{
				Resolve(won: true, "won");
			}
		}

		private static void Tell(long peer, string op, bool ok, string reason, ArenaView view, string extra)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(op ?? "");
			val.Write(ok);
			val.Write(reason ?? "");
			val.Write((view != null) ? Wire.ToJson(view) : "");
			val.Write(extra ?? "");
			RpcTally.Count("MPL_ArenaTell");
			ZRoutedRpc.instance.InvokeRoutedRPC(peer, "MPL_ArenaTell", new object[1] { val });
		}

		private static void OnTell(long sender, ZPackage package)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null || sender != ServerId())
			{
				return;
			}
			string arg;
			bool arg2;
			string arg3;
			string text;
			string arg4;
			try
			{
				arg = package.ReadString() ?? "";
				arg2 = package.ReadBool();
				arg3 = package.ReadString() ?? "";
				text = package.ReadString() ?? "";
				arg4 = package.ReadString() ?? "";
			}
			catch (Exception)
			{
				return;
			}
			if (text.Length > 0)
			{
				ArenaView arenaView = null;
				try
				{
					arenaView = Wire.FromJson<ArenaView>(text);
				}
				catch (Exception)
				{
				}
				if (arenaView != null)
				{
					arenaView.top = arenaView.top ?? new List<ArenaRow>();
					arenaView.owed = arenaView.owed ?? new List<Payout>();
					arenaView.busy = arenaView.busy ?? "";
					arenaView.seatName = arenaView.seatName ?? "";
					if (arenaView.bout != null && arenaView.bout.ticket == 0L)
					{
						arenaView.bout = null;
					}
					_view = arenaView;
					_skew = arenaView.now - DateTime.UtcNow.Ticks;
					Ready = true;
					Settle(localPlayer, arenaView);
				}
			}
			try
			{
				ArenaNet.Told?.Invoke(arg, arg2, arg3, arg4);
			}
			catch (Exception ex3)
			{
				Plugin.Log.LogError((object)("A Himinbjörg listener failed: " + ex3));
			}
		}

		private static ArenaClaim Claim(Player player)
		{
			if (_claim != null)
			{
				return _claim;
			}
			try
			{
				string text = PlayerDataApi.Get(player, "MPL_Arena");
				_claim = (string.IsNullOrEmpty(text) ? null : Wire.FromJson<ArenaClaim>(text));
			}
			catch (Exception)
			{
				_claim = null;
			}
			_claim = _claim ?? new ArenaClaim();
			_claim.paid = _claim.paid ?? new List<long>();
			return _claim;
		}

		private static void Settle(Player player, ArenaView view)
		{
			ArenaClaim arenaClaim = Claim(player);
			foreach (Payout item in view.owed)
			{
				if (item == null)
				{
					continue;
				}
				if (!arenaClaim.paid.Contains(item.id))
				{
					arenaClaim.paid.Add(item.id);
					while (arenaClaim.paid.Count > 24)
					{
						arenaClaim.paid.RemoveAt(0);
					}
					PlayerDataApi.Set(player, "MPL_Arena", Wire.ToJson(arenaClaim));
					QuestNet.GiveCoins(player, item.coins);
					QuestNet.GiveItem(player, item.item, item.count);
					if (item.megin > 0f && Lodge.RankOf(player) >= Rank.Veidimadr)
					{
						Lodge.RaiseMegin(item.megin * Validation.LevelNeed(Lodge.MeginLevel(player)), reward: true);
					}
					string text = TextApi.T("lodgea_paid", new object[1] { QuestText.Pay(item) });
					if (item.star > 0)
					{
						text = text + "\n" + TextApi.T("lodgea_milestone", new object[2]
						{
							item.star,
							TextApi.T("lodgea_title_" + item.star, Array.Empty<object>())
						});
					}
					((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false);
					if (item.standing > 0 && QuestSettings.On)
					{
						QuestNet.SendHello(force: true);
					}
				}
				Ask("ack", item.id.ToString(CultureInfo.InvariantCulture));
			}
		}

		internal static void Admin(long player, bool max)
		{
			ArenaRecord arenaRecord = ArenaRules.Find(Book(), player);
			if (arenaRecord != null)
			{
				if (max)
				{
					arenaRecord.nextAt = 0L;
				}
				else
				{
					AdminRules.FreshArena(arenaRecord);
				}
				Save();
			}
		}
	}
	public static class ArenaRules
	{
		private sealed class Dice
		{
			private ulong _state;

			public Dice(long seed)
			{
				_state = (ulong)(seed ^ -7046029254386353131L);
				if (_state == 0L)
				{
					_state = 2685821657736338717uL;
				}
			}

			public int Next(int below)
			{
				_state ^= _state << 13;
				_state ^= _state >> 7;
				_state ^= _state << 17;
				if (below > 1)
				{
					return (int)(_state % (ulong)below);
				}
				return 0;
			}
		}

		public const int TopFloor = 200;

		public const int ChampionEvery = 10;

		public const int SeatFloor = 200;

		public const int HalfFeeFloor = 50;

		public const int HalfWaitFloor = 100;

		public const int BookLimit = 2000;

		public const int TopRows = 10;

		public const int NeedRank = 2;

		public const int SendOffSeconds = 30;

		public const int OwedLimit = 12;

		public const int GraceSeconds = 15;

		public const string Gauntlet = "gauntlet";

		public const string Champion = "champion";

		public const string Seat = "seat";

		public const string OpClimb = "climb";

		public const string OpSeat = "seat";

		public const string Rune = "MP_Runestone";

		public const string Off = "off";

		public const string Unjoined = "unjoined";

		public const string LowRank = "rank";

		public const string Far = "far";

		public const string Busy = "busy";

		public const string Wait = "wait";

		public const string Coin = "coin";

		public const string AtTop = "top";

		public const string NotTop = "not_top";

		public const string Held = "held";

		public const string Stale = "stale";

		public const string Qualified = "qualified";

		public const string NoHall = "no_hall";

		public const string Inside = "inside";

		public const string Dead = "dead";

		public const string Fight = "fight";

		public const string Items = "items";

		public const string Soon = "soon";

		public static readonly int[] Milestones = new int[4] { 10, 50, 100, 200 };

		public static readonly int[] MilestoneRunes = new int[4] { 2, 4, 8, 12 };

		private static readonly string[] FallbackFoes = new string[3] { "Greyling", "Neck", "Boar" };

		public static long Ticks(double seconds)
		{
			return (long)(seconds * 10000000.0);
		}

		public static double Seconds(long ticks)
		{
			return (double)ticks / 10000000.0;
		}

		private static int Clamp(int value, int low, int high)
		{
			if (value >= low)
			{
				if (value <= high)
				{
					return value;
				}
				return high;
			}
			return low;
		}

		public static bool Qualifies(int rank)
		{
			return rank >= 2;
		}

		public static string SendOff(ArenaContext ctx, bool hallKnown, bool inside, bool dead, long lastSent)
		{
			if (ctx == null || !ctx.On)
			{
				return "off";
			}
			if (Qualifies(ctx.Rank))
			{
				return "qualified";
			}
			if (inside)
			{
				return "inside";
			}
			if (!ctx.Near)
			{
				return "far";
			}
			if (dead)
			{
				return "dead";
			}
			if (!hallKnown)
			{
				return "no_hall";
			}
			if (lastSent > 0 && ctx.Now - lastSent < Ticks(30.0))
			{
				return "soon";
			}
			return "";
		}

		public static string TripBlock(bool dead, bool fighting, bool inside, bool teleportable)
		{
			if (dead)
			{
				return "dead";
			}
			if (inside)
			{
				return "inside";
			}
			if (fighting)
			{
				return "fight";
			}
			if (!teleportable)
			{
				return "items";
			}
			return "";
		}

		public static string TrialElder(int rank, bool questsOn, int examState, int examStage, List<string> examPlan, string firstKind, Func<string, string> elderOf)
		{
			if (rank >= 1 || !questsOn || examState == 2 || elderOf == null)
			{
				return "hringvordr";
			}
			string text = TrialKind(examState, examStage, examPlan, firstKind);
			string text2 = ((text.Length > 0) ? elderOf(text) : null);
			if (!string.IsNullOrEmpty(text2))
			{
				return text2;
			}
			return "hringvordr";
		}

		public static string TrialKind(int examState, int examStage, List<string> examPlan, string firstKind)
		{
			if (examState != 2 && examPlan != null && examStage >= 0 && examStage < examPlan.Count)
			{
				string text = examPlan[examStage] ?? "";
				int num = text.IndexOf(':');
				if (num <= 0)
				{
					return text;
				}
				return text.Substring(0, num);
			}
			return firstKind ?? "";
		}

		public static bool IsChampion(int floor)
		{
			if (floor > 0)
			{
				return floor % 10 == 0;
			}
			return false;
		}

		public static int Next(ArenaRecord record)
		{
			if (record != null)
			{
				return Clamp(record.floor + 1, 1, 200);
			}
			return 1;
		}

		public static string KindOf(int floor)
		{
			if (!IsChampion(floor))
			{
				return "gauntlet";
			}
			return "champion";
		}

		public static int LandTier(int floor, int worldTier)
		{
			int num = Clamp(worldTier, 1, 7);
			return Clamp(Math.Max(1 + Math.Max(0, floor - 1) / 15, num - 2), 1, num);
		}

		public static bool HoldsSeat(ArenaSeat seat, long player)
		{
			if (seat != null && player != 0L)
			{
				return seat.player == player;
			}
			return false;
		}

		public static int Fee(int baseFee, ArenaRecord record, ArenaSeat seat)
		{
			int num = Math.Max(0, baseFee);
			if (record == null)
			{
				return num;
			}
			if (HoldsSeat(seat, record.player))
			{
				return 0;
			}
			if (record.floor < 50)
			{
				return num;
			}
			return num / 2;
		}

		public static int WaitMinutes(int minutes, ArenaRecord record)
		{
			int num = Math.Max(0, minutes);
			if (record == null || record.floor < 100)
			{
				return num;
			}
			return num / 2;
		}

		public static int TitleStep(int floor)
		{
			int result = 0;
			int[] milestones = Milestones;
			foreach (int num in milestones)
			{
				if (floor >= num)
				{
					result = num;
				}
			}
			return result;
		}

		public static int NextMilestone(int floor)
		{
			int[] milestones = Milestones;
			foreach (int num in milestones)
			{
				if (floor < num)
				{
					return num;
				}
			}
			return 0;
		}

		public static void Cap(ArenaRecord record, ArenaContext ctx)
		{
			if (record != null && ctx != null && record.nextAt > ctx.Now)
			{
				if (record.fightAt <= 0 || record.fightAt > ctx.Now)
				{
					record.fightAt = ctx.Now;
				}
				long num = record.fightAt + Ticks((double)WaitMinutes(ctx.WaitMinutes, record) * 60.0);
				if (num < record.nextAt)
				{
					record.nextAt = num;
				}
			}
		}

		public static double WaitLeft(ArenaRecord record, long now)
		{
			if (record != null && now < record.nextAt)
			{
				return Seconds(record.nextAt - now);
			}
			return 0.0;
		}

		public static ArenaRecord Find(ArenaBook book, long player)
		{
			if (book == null || player == 0L)
			{
				return null;
			}
			foreach (ArenaRecord hunter in book.hunters)
			{
				if (hunter != null && hunter.player == player)
				{
					return hunter;
				}
			}
			return null;
		}

		public static void Mend(ArenaBook book)
		{
			book.hunters = book.hunters ?? new List<ArenaRecord>();
			book.hunters.RemoveAll((ArenaRecord r) => r == null || r.player == 0);
			book.seat = book.seat ?? new ArenaSeat();
			book.seat.name = book.seat.name ?? "";
			foreach (ArenaRecord hunter in book.hunters)
			{
				hunter.name = hunter.name ?? "";
				hunter.milestones = hunter.milestones ?? new List<int>();
				hunter.owed = hunter.owed ?? new List<Payout>();
				hunter.owed.RemoveAll((Payout p) => p == null);
				hunter.floor = Clamp(hunter.floor, 0, 200);
			}
		}

		public static ArenaRecord Join(ArenaBook book, long player, string name, long now)
		{
			ArenaRecord arenaRecord = Find(book, player);
			if (arenaRecord != null)
			{
				if (!string.IsNullOrEmpty(name))
				{
					arenaRecord.name = name;
				}
				return arenaRecord;
			}
			if (player == 0L)
			{
				return null;
			}
			while (book.hunters.Count >= 2000)
			{
				ArenaRecord arenaRecord2 = null;
				foreach (ArenaRecord hunter in book.hunters)
				{
					if (!HoldsSeat(book.seat, hunter.player) && (arenaRecord2 == null || hunter.floor < arenaRecord2.floor || (hunter.floor == arenaRecord2.floor && hunter.joinedAt < arenaRecord2.joinedAt)))
					{
						arenaRecord2 = hunter;
					}
				}
				if (arenaRecord2 == null)
				{
					break;
				}
				book.hunters.Remove(arenaRecord2);
			}
			arenaRecord = new ArenaRecord
			{
				player = player,
				name = (name ?? ""),
				joinedAt = now
			};
			book.hunters.Add(arenaRecord);
			return arenaRecord;
		}

		public static string CanBegin(ArenaRecord record, ArenaContext ctx, string op, ArenaSeat seat, out int fee)
		{
			fee = 0;
			if (ctx == null || !ctx.On)
			{
				return "off";
			}
			if (record == null)
			{
				return "unjoined";
			}
			if (!Qualifies(ctx.Rank))
			{
				return "rank";
			}
			if (op == "seat")
			{
				if (record.floor < 200)
				{
					return "not_top";
				}
				if (HoldsSeat(seat, record.player))
				{
					return "held";
				}
			}
			else
			{
				if (!(op == "climb"))
				{
					return "stale";
				}
				if (record.floor >= 200)
				{
					return "top";
				}
			}
			if (!ctx.Near)
			{
				return "far";
			}
			if (!string.IsNullOrEmpty(ctx.Busy))
			{
				return "busy";
			}
			if (ctx.Now < record.nextAt)
			{
				return "wait";
			}
			fee = Fee(ctx.Fee, record, seat);
			if (ctx.Coins < fee)
			{
				return "coin";
			}
			return "";
		}

		private static string Pick(List<string> pool, Dice dice)
		{
			return pool[dice.Next(pool.Count)];
		}

		private static int Stars(int floor, Dice dice)
		{
			int num = dice.Next(100);
			if (floor >= 150)
			{
				if (num >= 35)
				{
					return (num < 85) ? 1 : 0;
				}
				return 2;
			}
			if (floor >= 100)
			{
				if (num >= 15)
				{
					return (num < 65) ? 1 : 0;
				}
				return 2;
			}
			if (floor >= 40)
			{
				return (num < 25) ? 1 : 0;
			}
			return 0;
		}

		public static int Waves(int floor)
		{
			return 1 + floor % 10 / 3;
		}

		public static int PerWave(int floor)
		{
			return Math.Min(6, 2 + floor / 40);
		}

		public static ArenaPlan Plan(int floor, string kind, int worldTier, long ticket, LandInfo land, IList<string> champions)
		{
			floor = Clamp(floor, 1, 200);
			ArenaPlan arenaPlan = new ArenaPlan
			{
				ticket = ticket,
				floor = floor,
				kind = kind,
				tier = (land?.tier ?? 1)
			};
			Dice dice = new Dice(ticket ^ ((long)floor * 7919L));
			List<string> list = ((land != null && land.wave.Count > 0) ? land.wave : new List<string>(FallbackFoes));
			List<string> pool = ((land != null && land.elite.Count > 0) ? land.elite : list);
			arenaPlan.head = Pick(pool, dice);
			if (kind == "gauntlet")
			{
				int num = Waves(floor);
				int num2 = PerWave(floor);
				float health = 1f + (float)floor / 150f;
				for (int i = 0; i < num; i++)
				{
					ArenaWave arenaWave = new ArenaWave();
					for (int j = 0; j < num2; j++)
					{
						bool flag = i == num - 1 && j == 0 && floor % 10 >= 5;
						arenaWave.foes.Add(new ArenaSpawn
						{
							prefab = (flag ? Pick(pool, dice) : Pick(list, dice)),
							stars = Stars(floor, dice),
							health = health,
							elite = flag
						});
					}
					arenaPlan.waves.Add(arenaWave);
				}
				arenaPlan.need = num * num2;
				arenaPlan.seconds = 90 + 60 * num;
				return arenaPlan;
			}
			int num3 = ((kind == "seat") ? 220 : floor);
			if (champions != null && champions.Count > 0)
			{
				arenaPlan.champion = ((kind == "seat") ? champions[dice.Next(champions.Count)] : champions[(num3 / 10 - 1) % champions.Count]);
			}
			arenaPlan.health = 1f + (float)num3 / 25f;
			arenaPlan.level = ((num3 >= 150) ? 3 : ((num3 < 60) ? 1 : 2));
			int num4 = ((kind == "seat") ? 4 : Math.Min(4, num3 / 50));
			for (int k = 0; k < num4; k++)
			{
				arenaPlan.escorts.Add(new ArenaSpawn
				{
					prefab = Pick(pool, dice),
					stars = ((kind == "seat") ? 2 : ((num3 >= 100) ? 1 : 0)),
					health = 1f + (float)num3 / 150f,
					elite = true
				});
			}
			arenaPlan.need = 1;
			arenaPlan.seconds = ((kind == "seat") ? 300 : 240);
			return arenaPlan;
		}

		public static int MinSeconds(ArenaPlan plan)
		{
			if (plan == null)
			{
				return 0;
			}
			if (!(plan.kind == "gauntlet"))
			{
				return 8;
			}
			return plan.waves.Count * 4 + 2;
		}

		public static void Start(ArenaPlan plan, long now)
		{
			plan.startedAt = now;
			plan.deadline = now + Ticks(plan.seconds);
		}

		public static bool Expired(ArenaPlan plan, long now)
		{
			if (plan != null)
			{
				return now > plan.deadline + Ticks(15.0);
			}
			return false;
		}

		public static bool Count(ArenaBout bout, string id, bool head, long now)
		{
			if (bout == null || bout.Plan == null || string.IsNullOrEmpty(id) || bout.Counted.Contains(id))
			{
				return false;
			}
			if (now < bout.Plan.startedAt + Ticks(2.0) || now > bout.Plan.deadline + Ticks(15.0))
			{
				return false;
			}
			if (bout.Plan.kind != "gauntlet" && !head)
			{
				return false;
			}
			bout.Counted.Add(id);
			bout.Kills++;
			return true;
		}

		public static bool Won(ArenaBout bout, long now)
		{
			if (bout != null && bout.Plan != null && bout.Kills >= bout.Plan.need)
			{
				return now >= bout.Plan.startedAt + Ticks(MinSeconds(bout.Plan));
			}
			return false;
		}

		public static Payout Reward(int floor, string kind, int worldTier, float strength, bool quests)
		{
			float num = Math.Max(0f, Math.Min(5f, strength));
			int num2 = Clamp(worldTier, 1, 7);
			double num3 = 1.0 + 0.15 * (double)(num2 - 1);
			double num4 = (double)(15 + 3 * floor) * num3;
			int num5 = 1 + floor / 10;
			double num6 = Math.Min(0.5, 0.04 + (double)floor * 0.001);
			if (kind == "champion")
			{
				num4 *= 3.0;
				num5 *= 3;
				num6 = Math.Min(0.6, num6 * 2.0);
			}
			else if (kind == "seat")
			{
				num4 = 1500.0 * num3;
				num5 = 60;
				num6 = 0.6;
			}
			return new Payout
			{
				coins = (int)Math.Round(num4 * (double)num),
				standing = (quests ? num5 : 0),
				megin = (float)Math.Round(Math.Min(1.0, num6 * (double)num), 3)
			};
		}

		public static Payout Win(ArenaBook book, ArenaRecord record, ArenaPlan plan, ArenaContext ctx)
		{
			Payout payout = Reward(plan.floor, plan.kind, ctx.WorldTier, ctx.Strength, ctx.Quests);
			payout.id = Math.Max(ctx.Now, record.payId + 1);
			record.payId = payout.id;
			payout.job = "arena";
			payout.key = plan.kind + ":" + plan.floor;
			if (plan.kind == "seat")
			{
				book.seat = new ArenaSeat
				{
					player = record.player,
					name = record.name,
					since = ctx.Now,
					held = ((book.seat != null) ? book.seat.held : 0) + 1
				};
			}
			else if (plan.floor == record.floor + 1)
			{
				record.floor = plan.floor;
				record.reachedAt = ctx.Now;
				int num = Array.IndexOf(Milestones, plan.floor);
				if (num >= 0 && !record.milestones.Contains(plan.floor))
				{
					record.milestones.Add(plan.floor);
					payout.item = "MP_Runestone";
					payout.count = MilestoneRunes[num];
					payout.star = plan.floor;
				}
			}
			record.wins++;
			record.fightAt = ctx.Now;
			record.nextAt = ctx.Now + Ticks((double)WaitMinutes(ctx.WaitMinutes, record) * 60.0);
			record.owed.Add(payout);
			while (record.owed.Count > 12)
			{
				record.owed.RemoveAt(0);
			}
			return payout;
		}

		public static void Lose(ArenaRecord record, ArenaContext ctx)
		{
			if (record != null)
			{
				record.losses++;
				record.fightAt = ctx.Now;
				record.nextAt = ctx.Now + Ticks((double)WaitMinutes(ctx.WaitMinutes, record) * 60.0);
			}
		}

		public static bool Ack(ArenaRecord record, long id)
		{
			if (record != null)
			{
				return record.owed.RemoveAll((Payout p) => p.id == id) > 0;
			}
			return false;
		}

		public static List<ArenaRow> Top(ArenaBook book, int count)
		{
			List<ArenaRecord> list = new List<ArenaRecord>();
			foreach (ArenaRecord hunter in book.hunters)
			{
				if (hunter != null && (hunter.floor > 0 || HoldsSeat(book.seat, hunter.player)))
				{
					list.Add(hunter);
				}
			}
			list.Sort(delegate(ArenaRecord a, ArenaRecord b)
			{
				int num2 = (HoldsSeat(book.seat, a.player) ? 1 : 0);
				int num3 = (HoldsSeat(book.seat, b.player) ? 1 : 0);
				if (num2 != num3)
				{
					return num3.CompareTo(num2);
				}
				if (a.floor != b.floor)
				{
					return b.floor.CompareTo(a.floor);
				}
				return (a.reachedAt != b.reachedAt) ? a.reachedAt.CompareTo(b.reachedAt) : string.CompareOrdinal(a.name, b.name);
			});
			List<ArenaRow> list2 = new List<ArenaRow>();
			for (int num = 0; num < list.Count; num++)
			{
				if (list2.Count >= count)
				{
					break;
				}
				list2.Add(new ArenaRow
				{
					name = list[num].name,
					floor = list[num].floor,
					wins = list[num].wins,
					seat = HoldsSeat(book.seat, list[num].player)
				});
			}
			return list2;
		}

		public static ArenaView View(ArenaBook book, ArenaRecord record, ArenaContext ctx, ArenaBout bout)
		{
			ArenaView arenaView = new ArenaView
			{
				on = ctx.On,
				now = ctx.Now,
				tier = ctx.WorldTier,
				busy = (ctx.