Decompiled source of HiredHands v0.12.1

plugins/HiredHands.dll

Decompiled 11 hours 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 System.Threading;
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 Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using VikingsForHire.Board;
using VikingsForHire.Commands;
using VikingsForHire.Compat;
using VikingsForHire.Config;
using VikingsForHire.Core;
using VikingsForHire.Core.Chores;
using VikingsForHire.Core.Data;
using VikingsForHire.Core.Diagnostics;
using VikingsForHire.Core.Enhancements;
using VikingsForHire.Core.Nav;
using VikingsForHire.Core.Orders;
using VikingsForHire.Core.Testing;
using VikingsForHire.Diagnostics;
using VikingsForHire.Followers;
using VikingsForHire.Hirelings;
using VikingsForHire.Hirelings.Combat;
using VikingsForHire.Hirelings.Gear;
using VikingsForHire.Hirelings.Nav;
using VikingsForHire.Hirelings.Work;
using VikingsForHire.Hirelings.Work.Chores;
using VikingsForHire.Hirelings.Work.Farm;
using VikingsForHire.Hirelings.Work.Kitchen;
using VikingsForHire.Hirelings.Work.Ranch;
using VikingsForHire.Hirelings.Work.Steward;
using VikingsForHire.Hirelings.Work.Trees;
using VikingsForHire.L10n;
using VikingsForHire.Net;
using VikingsForHire.Telemetry;
using VikingsForHire.Testing;
using VikingsForHire.UI;
using YamlDotNet.Core;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace VikingsForHire
{
	[BepInPlugin("Spronglehump.HiredHands", "HiredHands", "0.12.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "Spronglehump.HiredHands";

		public const string Name = "HiredHands";

		public const string Version = "0.12.1";

		internal static ManualLogSource Log;

		internal static Harmony Harmony;

		internal static Plugin Instance;

		private void Awake()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			VfhLog.Init(((BaseUnityPlugin)this).Logger);
			VfhConfig.Bind(((BaseUnityPlugin)this).Config);
			DataStore.Init();
			Strings.Register();
			Harmony = new Harmony("Spronglehump.HiredHands");
			Harmony.PatchAll(typeof(Plugin).Assembly);
			CompatPatcher.Apply(Harmony);
			BoardPiece.Register();
			CommandStoneItem.Register();
			HiringCharter.Register();
			BroomItem.Register();
			CultivatorItem.Register();
			LadleItem.Register();
			ChefHatItem.Register();
			TreePatchPiece.Register();
			CropCatalog.Register();
			FarmState.FreeSpots = PlantChore.FreeSpots;
			KitchenCatalog.Register();
			FollowerServer.Register();
			BalanceLog.Register();
			ClientLogRelay.Register();
			LowFunds.Register();
			HirelingMapPins.Register();
			BoardRegistry.Register();
			MutationService.Register();
			BoardServer.Register();
			CharterPacking.Register();
			HirelingPrefab.Register();
			DebugCommands.Register();
			BoardCommands.Register();
			HirelingCommands.Register();
			NavCommands.Register();
			RosterCommands.Register();
			TestHarness.Register();
			Fixtures.Register();
			FixturesBoard.Register();
			FixturesUpgrade.Register();
			FixturesHireling.Register();
			FixturesRoster.Register();
			FixturesCombat.Register();
			FixturesWork.Register();
			FixturesMining.Register();
			FixturesSmelter.Register();
			FixturesFollow.Register();
			FixturesTravel.Register();
			FixturesNav.Register();
			FixturesFarm.Register();
			FixturesKitchen.Register();
			SessionInfo.LogHeader("plugin load");
			Log.LogInfo((object)"HiredHands 0.12.1 loaded");
		}

		private void Update()
		{
			PerfCounters.FrameTick();
			VfhLog.Guard(LogCat.Data, "data.tick_failed", DataStore.Tick);
			VfhLog.Guard(LogCat.Board, "upgrade.tick_failed", BoardUpgrade.Tick);
			VfhLog.Guard(LogCat.Roster, "server.tick_failed", BoardServer.Tick);
			VfhLog.Guard(LogCat.Follow, "follow.tick_failed", FollowerServer.Tick);
			VfhLog.Guard(LogCat.Follow, "orphan.tick_failed", OrphanMonitor.Tick);
			VfhLog.Guard(LogCat.Follow, "ghost.tick_failed", HirelingGhostGuard.Tick);
			VfhLog.Guard(LogCat.Roster, "reconcile.tick_failed", RosterReconciler.Tick);
			VfhLog.Guard(LogCat.Core, "balance.tick_failed", BalanceLog.Tick);
			VfhLog.Guard(LogCat.Core, "clientlog.tick_failed", ClientLogRelay.Tick);
			StoneInput.Tick();
			VfhLog.Guard(LogCat.Follow, "travel.tick_failed", TeleportTravel.Tick);
			VfhLog.Guard(LogCat.Follow, "claim.tick_failed", TeleportTravel.ClaimFollowers);
			VfhLog.Guard(LogCat.Follow, "ship.tick_failed", ShipStowage.Tick);
			VfhLog.Guard(LogCat.UI, "hud.tick_failed", FollowerHud.Tick);
			VfhLog.Guard(LogCat.Board, "funds.tick_failed", LowFunds.Tick);
			VfhLog.Guard(LogCat.Follow, "pins.tick_failed", HirelingMapPins.Tick);
			VfhLog.Guard(LogCat.Hireling, "chatter.tick_failed", HirelingChatter.Tick);
			VfhLog.Guard(LogCat.Combat, "summons.tick_failed", SummonedAllies.Tick);
			VfhLog.Guard(LogCat.Smelter, "bonesetter.tick_failed", Bonesetter.Tick);
			VfhLog.Guard(LogCat.Work, "rancher.tick_failed", RancherTicker.Tick);
			VfhLog.Guard(LogCat.Hireling, "graves.tick_failed", Graves.Tick);
			VfhLog.Guard(LogCat.Nav, "navlinks.tick_failed", NavLinkRegistry.Tick);
		}

		private void OnDestroy()
		{
			ClientLogRelay.Shutdown();
			VfhLog.Shutdown();
		}
	}
}
namespace VikingsForHire.UI
{
	internal sealed class AreaRing : MonoBehaviour
	{
		private const float HoldSeconds = 0.3f;

		private const int Points = 96;

		private LineRenderer? _line;

		private float _showUntil;

		private float _radius = -1f;

		private float _drawn = -1f;

		private Vector3 _drawnAt;

		private Color _color = new Color(0.4f, 1f, 0.4f, 0.8f);

		public static AreaRing On(Component owner, Color color)
		{
			//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)
			AreaRing areaRing = owner.GetComponent<AreaRing>();
			if ((Object)(object)areaRing == (Object)null)
			{
				areaRing = owner.gameObject.AddComponent<AreaRing>();
			}
			areaRing._color = color;
			return areaRing;
		}

		public void Show(float radius)
		{
			_radius = radius;
			_showUntil = Time.time + 0.3f;
		}

		private void Update()
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: 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)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: 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_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: 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)
			if (Time.time >= _showUntil)
			{
				if ((Object)(object)_line != (Object)null && ((Renderer)_line).enabled)
				{
					((Renderer)_line).enabled = false;
				}
				return;
			}
			if ((Object)(object)_line == (Object)null)
			{
				GameObject val = new GameObject("VFH_AreaRing");
				val.transform.SetParent(((Component)this).transform, false);
				_line = val.AddComponent<LineRenderer>();
				_line.useWorldSpace = true;
				_line.loop = true;
				_line.widthMultiplier = 0.08f;
				((Renderer)_line).material = new Material(Shader.Find("Sprites/Default"));
			}
			LineRenderer? line = _line;
			Color startColor = (_line.endColor = _color);
			line.startColor = startColor;
			((Renderer)_line).enabled = true;
			if (Mathf.Abs(_drawn - _radius) <= 0.01f)
			{
				Vector3 val2 = ((Component)this).transform.position - _drawnAt;
				if (((Vector3)(ref val2)).sqrMagnitude < 0.0025f && _line.positionCount > 0 && Time.frameCount % 30 != 0)
				{
					return;
				}
			}
			_drawn = _radius;
			_drawnAt = ((Component)this).transform.position;
			_line.positionCount = 96;
			for (int i = 0; i < 96; i++)
			{
				float num = (float)i * (float)Math.PI * 2f / 96f;
				Vector3 val3 = ((Component)this).transform.position + new Vector3(Mathf.Cos(num), 0f, Mathf.Sin(num)) * _radius;
				val3.y = (((Object)(object)ZoneSystem.instance != (Object)null) ? ZoneSystem.instance.GetGroundHeight(val3) : val3.y) + 0.15f;
				_line.SetPosition(i, val3);
			}
		}
	}
	internal sealed class BoardPanel : MonoBehaviour
	{
		[HarmonyPatch(typeof(Menu), "Update")]
		private static class MenuPatch
		{
			private static bool Prefix()
			{
				long timestamp = Stopwatch.GetTimestamp();
				try
				{
					if (!IsOpen && !HirelingPanel.IsOpen)
					{
						return true;
					}
					if (ZInput.GetKeyDown((KeyCode)27, true) || ZInput.GetButtonDown("JoyButtonB"))
					{
						Close("escape");
						return false;
					}
					return true;
				}
				catch (Exception ex)
				{
					VfhLog.PatchFailed("BoardPanel.MenuUpdate", ex);
					return true;
				}
				finally
				{
					PerfCounters.Patch("BoardPanel.MenuUpdate", timestamp);
				}
			}
		}

		private const float OpenRange = 5f;

		private const float PanelWidth = 1000f;

		private const float PanelHeight = 720f;

		private const float TabSpacing = 210f;

		private const float CloseRange = 6f;

		private const float RefreshSeconds = 0.5f;

		private static BoardPanel? _instance;

		private readonly List<IBoardTab> _tabs = new List<IBoardTab>
		{
			new ContractsTab(),
			new RosterTab(),
			new OrdersTab(),
			new UpgradeTab()
		};

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

		private HiringBoard? _board;

		private RectTransform _content;

		private Text _title;

		private int _tab;

		private string _shown = "";

		private float _nextRefresh;

		public static bool IsOpen
		{
			get
			{
				if ((Object)(object)_instance != (Object)null)
				{
					return ((Component)_instance).gameObject.activeSelf;
				}
				return false;
			}
		}

		public static void Open(HiringBoard board, int tab = 0)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !GUIManager.IsHeadless() && !(Vector3.Distance(((Component)localPlayer).transform.position, ((Component)board).transform.position) > 5f) && PrivateArea.CheckAccess(((Component)board).transform.position, 0f, true, false))
			{
				if ((Object)(object)_instance == (Object)null)
				{
					_instance = Create();
				}
				_instance._board = board;
				_instance._tab = tab;
				_instance._shown = "";
				_instance._nextRefresh = 0f;
				((Component)_instance).gameObject.SetActive(true);
				GUIManager.BlockInput(true);
				VfhLog.D(LogCat.UI, "panel.open", ("board", board.Id), ("tab", tab));
			}
		}

		public static void Close(string reason)
		{
			if (IsOpen)
			{
				((Component)_instance).gameObject.SetActive(false);
				GUIManager.BlockInput(false);
				VfhLog.D(LogCat.UI, "panel.close", ("board", ((Object)(object)_instance._board != (Object)null) ? _instance._board.Id : ""), ("reason", reason));
				_instance._board = null;
			}
		}

		private static BoardPanel Create()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 1000f, 720f, false);
			((Object)val).name = "VFH_BoardPanel";
			BoardPanel panel = val.AddComponent<BoardPanel>();
			panel._title = PanelUi.Text(val.transform, "$vfh_board", 0f, -40f, 640f, 28, (TextAnchor)4, null, bold: true);
			for (int i = 0; i < panel._tabs.Count; i++)
			{
				int index = i;
				panel._tabButtons.Add(PanelUi.Button(val.transform, panel._tabs[i].Title, ((float)i - (float)(panel._tabs.Count - 1) / 2f) * 210f, -95f, 190f, 40f, delegate
				{
					panel.SelectTab(index);
				}));
			}
			panel._content = PanelUi.Fill(val.transform, "content");
			PanelUi.Button(val.transform, "$vfh_close", 410f, -35f, 90f, 36f, delegate
			{
				Close("button");
			});
			val.SetActive(false);
			PanelUi.Clicked += delegate
			{
				if ((Object)(object)_instance != (Object)null)
				{
					_instance._nextRefresh = 0f;
				}
			};
			return panel;
		}

		private void SelectTab(int index)
		{
			_tab = index;
			_shown = "";
			_nextRefresh = 0f;
			VfhLog.D(LogCat.UI, "panel.tab", ("tab", _tabs[index].Title));
		}

		private void Update()
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_board == (Object)null || _board.Zdo == null)
			{
				Close("board gone");
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || Vector3.Distance(((Component)localPlayer).transform.position, ((Component)_board).transform.position) > 6f)
			{
				Close("walked away");
				return;
			}
			_board.ShowArea();
			if (Time.unscaledTime < _nextRefresh)
			{
				return;
			}
			_nextRefresh = Time.unscaledTime + 0.5f;
			VfhLog.Guard(LogCat.UI, "panel.refresh_failed", delegate
			{
				//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				IBoardTab boardTab = _tabs[_tab];
				string text = _tab + "|" + boardTab.Signature(_board);
				if (!(text == _shown))
				{
					_shown = text;
					_title.text = Localization.instance.Localize("$vfh_board — $vfh_level ") + _board.Level;
					for (int i = 0; i < _tabButtons.Count; i++)
					{
						((Graphic)((Component)_tabButtons[i]).GetComponentInChildren<Text>()).color = ((i == _tab) ? GUIManager.Instance.ValheimOrange : GUIManager.Instance.ValheimBeige);
					}
					PanelUi.Clear((Transform)(object)_content);
					boardTab.Build(_content, _board);
				}
			}, ("board", _board.Id));
		}

		private void OnDestroy()
		{
			if ((Object)(object)_instance == (Object)(object)this)
			{
				if (((Component)this).gameObject.activeSelf)
				{
					GUIManager.BlockInput(false);
				}
				_instance = null;
			}
		}
	}
	internal sealed class ContractsTab : IBoardTab
	{
		private static readonly JobType[] AllJobs = (JobType[])Enum.GetValues(typeof(JobType));

		private static readonly JobType[] WorkerJobs = Array.FindAll(AllJobs, (JobType j) => !j.IsCombat());

		private const float RadiusStep = 5f;

		private int _job;

		private int _level = 1;

		private float _radius = 20f;

		private string _radiusDefaultedFor = "";

		private int _stance = -1;

		private static JobType[] Jobs
		{
			get
			{
				if (!VfhConfig.CombatHirelings.Value)
				{
					return WorkerJobs;
				}
				return AllJobs;
			}
		}

		public string Title => "$vfh_tab_contracts";

		public string Signature(HiringBoard board)
		{
			Clamp(board);
			Cost cost = ((board.Inventory != null) ? BoardStorage.Totals(board.Inventory) : Cost.Zero);
			int num = ((board.Zdo != null) ? BoardRosterOps.Read(board.Zdo).Count : 0);
			return $"{_job}|{_level}|{_radius}|{_stance}|{board.Level}|{cost}|{num}|{DataStore.Hash}|{VfhConfig.CombatHirelings.Value}";
		}

		public void Build(RectTransform root, HiringBoard board)
		{
			//IL_03d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_04db: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0568: Unknown result type (might be due to invalid IL or missing references)
			//IL_05b1: Unknown result type (might be due to invalid IL or missing references)
			Clamp(board);
			JobType job = Jobs[_job];
			IReadOnlyList<Stance> stances = StanceRules.Allowed(job);
			Stance stance = stances[_stance];
			LevelRules levelRules = new LevelRules(DataStore.Current);
			CostCalculator costCalculator = new CostCalculator(DataStore.Current, VfhConfig.RespawnCostFraction.Value);
			Row(root, -150f, "$vfh_contract_job", "$vfh_job_" + job.ToString().ToLowerInvariant(), delegate
			{
				_job = (_job + Jobs.Length - 1) % Jobs.Length;
			}, delegate
			{
				_job = (_job + 1) % Jobs.Length;
			});
			Row(root, -195f, "$vfh_contract_level", _level.ToString(), delegate
			{
				_level--;
			}, delegate
			{
				_level++;
			});
			Row(root, -240f, "$vfh_contract_radius", $"{_radius:0} m", delegate
			{
				_radius -= 5f;
			}, delegate
			{
				_radius += 5f;
			});
			Row(root, -285f, "$vfh_contract_stance", "$vfh_stance_" + stance.ToString().ToLowerInvariant(), delegate
			{
				_stance = (_stance + stances.Count - 1) % stances.Count;
			}, delegate
			{
				_stance = (_stance + 1) % stances.Count;
			});
			Cost c = costCalculator.HireCost(job, _level);
			Cost c2 = costCalculator.DailyUpkeep(job, _level);
			Cost available = ((board.Inventory != null) ? BoardStorage.Totals(board.Inventory) : Cost.Zero);
			Roster roster = ((board.Zdo != null) ? BoardRosterOps.Read(board.Zdo) : new Roster());
			OpOutcome opOutcome = roster.CanPost(job, levelRules, board.Level);
			bool flag = opOutcome == OpOutcome.Ok;
			int num = roster.KindCount(combat: true);
			int num2 = roster.KindCount(combat: false);
			int num3 = levelRules.CombatCap(board.Level);
			int num4 = levelRules.WorkerCap(board.Level);
			int num5 = roster.JobCount(job);
			int num6 = levelRules.MaxPerBoard(job);
			string text = (VfhConfig.CombatHirelings.Value ? Localization.instance.Localize("$vfh_contract_counts", new string[4]
			{
				num.ToString(),
				num3.ToString(),
				num2.ToString(),
				num4.ToString()
			}) : Localization.instance.Localize("$vfh_contract_counts_workers", new string[2]
			{
				num2.ToString(),
				num4.ToString()
			}));
			if (num6 > 0)
			{
				text += Localization.instance.Localize("$vfh_contract_job_count", new string[3]
				{
					Localization.instance.Localize("$vfh_job_" + job.ToString().ToLowerInvariant()),
					num5.ToString(),
					num6.ToString()
				});
			}
			bool flag2 = (job.IsCombat() ? (num >= num3) : (num2 >= num4)) || (num6 > 0 && num5 >= num6);
			bool flag3 = c.CoveredBy(available);
			bool flag4 = levelRules.JobUnlocked(board.Level, job);
			PanelUi.Text((Transform)(object)root, Localization.instance.Localize("$vfh_contract_fee") + "  " + Price(c), 0f, -335f, 600f, 18, (TextAnchor)4, flag3 ? PanelUi.Good : PanelUi.Bad);
			PanelUi.Text((Transform)(object)root, Localization.instance.Localize("$vfh_contract_upkeep") + "  " + Price(c2), 0f, -365f, 600f, 18, (TextAnchor)4);
			PanelUi.Text((Transform)(object)root, Localization.instance.Localize("$vfh_contract_funds") + "  " + string.Format("{0} {1} + {2} {3}", available.FoodPoints, Localization.instance.Localize("$vfh_food_points"), available.Coins, Localization.instance.Localize("$vfh_coins")), 0f, -395f, 600f, 18, (TextAnchor)4, PanelUi.Dim);
			PanelUi.Text((Transform)(object)root, text, 0f, -425f, 600f, 18, (TextAnchor)4, flag2 ? PanelUi.Bad : PanelUi.Dim);
			((Selectable)PanelUi.Button((Transform)(object)root, "$vfh_contract_post", 0f, -475f, 240f, 44f, delegate
			{
				BoardContracts.Post(board, job, _level, _radius, stance);
			})).interactable = flag3 && flag && flag4;
			if (!flag4)
			{
				PanelUi.Text((Transform)(object)root, Localization.instance.Localize("$vfh_contract_job_locked", new string[1] { levelRules.MinBoardLevel(job).ToString() }), 0f, -515f, 600f, 18, (TextAnchor)4, PanelUi.Bad);
			}
			else if (!flag)
			{
				PanelUi.Text((Transform)(object)root, BoardContracts.Text(BoardRosterOps.RefusalMessage(opOutcome, job, roster, levelRules, board.Level)), 0f, -515f, 600f, 18, (TextAnchor)4, PanelUi.Bad);
			}
		}

		public static string Price(Cost c)
		{
			List<string> list = new List<string>();
			if (c.FoodPoints > 0)
			{
				list.Add(string.Format("{0} {1}", c.FoodPoints, Localization.instance.Localize("$vfh_food_points")));
			}
			if (c.Coins > 0)
			{
				list.Add(string.Format("{0} {1}", c.Coins, Localization.instance.Localize("$vfh_coins")));
			}
			if (list.Count <= 0)
			{
				return Localization.instance.Localize("$vfh_free");
			}
			return string.Join(" + ", list);
		}

		private void Clamp(HiringBoard board)
		{
			_job %= Jobs.Length;
			LevelRules levelRules = new LevelRules(DataStore.Current);
			_level = Mathf.Clamp(_level, 1, levelRules.MaxHirelingLevel(board.Level));
			float num = levelRules.MaxWorkRadius(board.Level, Jobs[_job]);
			string text = $"{Jobs[_job]}|{board.Level}";
			if (text != _radiusDefaultedFor)
			{
				_radiusDefaultedFor = text;
				_radius = num;
			}
			_radius = Mathf.Clamp(_radius, 10f, num);
			int count = StanceRules.Allowed(Jobs[_job]).Count;
			if (_stance < 0 || _stance >= count)
			{
				_stance = IndexOf(StanceRules.Allowed(Jobs[_job]), StanceRules.Default(Jobs[_job]));
			}
		}

		private static int IndexOf(IReadOnlyList<Stance> list, Stance s)
		{
			for (int i = 0; i < list.Count; i++)
			{
				if (list[i] == s)
				{
					return i;
				}
			}
			return 0;
		}

		private static void Row(RectTransform root, float y, string label, string value, Action prev, Action next)
		{
			PanelUi.Text((Transform)(object)root, label, -200f, y, 180f, 20, (TextAnchor)3);
			PanelUi.Button((Transform)(object)root, "<", -30f, y, 44f, 36f, prev);
			PanelUi.Text((Transform)(object)root, value, 90f, y, 180f, 20, (TextAnchor)4, null, bold: true);
			PanelUi.Button((Transform)(object)root, ">", 210f, y, 44f, 36f, next);
		}
	}
	internal sealed class HirelingPanel : MonoBehaviour
	{
		private sealed class RenameReceiver : TextReceiver
		{
			private readonly Hireling _h;

			private readonly string _hid;

			private readonly string _boardId;

			public RenameReceiver(Hireling h)
			{
				_h = h;
				_hid = h.Hid;
				_boardId = h.BoardId;
			}

			public string GetText()
			{
				if (!((Object)(object)_h != (Object)null))
				{
					return "";
				}
				return _h.DisplayName;
			}

			public void SetText(string text)
			{
				string text2 = HirelingNames.Clean(text);
				if (text2.Length != 0)
				{
					if (_boardId.Length > 0)
					{
						MutationService.SubmitBoard(_boardId, new RosterOp
						{
							Type = RosterOpType.Rename,
							Hid = _hid,
							Name = text2
						});
					}
					else
					{
						MutationService.SubmitHireling(_hid, new HirelingOp
						{
							Name = text2
						});
					}
					VfhLog.I(LogCat.UI, "hireling.rename", ("hid", _hid), ("name", text2));
				}
			}
		}

		private const float OpenRange = 6f;

		private const float CloseRange = 8f;

		private const float GroupRange = 30f;

		private static HirelingPanel? _instance;

		private Hireling? _hireling;

		private float _nextHold;

		private RectTransform _content;

		private RectTransform? _close;

		private bool _all;

		private bool _orders;

		private bool _ordersPicking;

		private int _ordersPage;

		private InputField? _search;

		private string _ordersSearch = "";

		private bool _why;

		private int _whyPage;

		private bool _enh;

		private int _pendingLevel;

		private char _pendingChoice;

		private string _shown = "";

		private float _nextRefresh;

		private const float MinHeight = 420f;

		private const float EnhWidth = 760f;

		private const float EnhRowHeight = 74f;

		private const float Width = 520f;

		private const float LimitsWidth = 660f;

		private const int LimitPicksPerPage = 12;

		private const int OrderPicksPerPage = 14;

		private const int WhyRowsPerPage = 10;

		public static bool IsOpen
		{
			get
			{
				if ((Object)(object)_instance != (Object)null)
				{
					return ((Component)_instance).gameObject.activeSelf;
				}
				return false;
			}
		}

		public static void Open(Hireling h)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || GUIManager.IsHeadless() || Vector3.Distance(((Component)localPlayer).transform.position, ((Component)h).transform.position) > 6f)
			{
				return;
			}
			bool flag = h.Mode == HirelingMode.Following;
			if (flag && h.OwnerId != localPlayer.GetPlayerID())
			{
				((Character)localPlayer).Message((MessageType)2, Localization.instance.Localize("$vfh_not_your_follower"), 0, (Sprite)null, false);
			}
			else if (flag || PrivateArea.CheckAccess(h.Home, 0f, true, false))
			{
				if ((Object)(object)_instance == (Object)null)
				{
					_instance = Create();
				}
				_instance._hireling = h;
				_instance._shown = "";
				_instance._orders = false;
				_instance._ordersPicking = false;
				_instance._ordersPage = 0;
				_instance.ClearSearch();
				_instance._why = false;
				_instance._whyPage = 0;
				_instance._enh = false;
				_instance._pendingLevel = 0;
				_instance._nextRefresh = 0f;
				_instance._nextHold = 0f;
				((Component)_instance).gameObject.SetActive(true);
				GUIManager.BlockInput(true);
				VfhLog.D(LogCat.UI, "orders.open", ("hid", h.Hid));
			}
		}

		public static void ShowPage(string page)
		{
			if (!((Object)(object)_instance == (Object)null))
			{
				HirelingPanel instance = _instance;
				bool orders = ((page == "orders" || page == "orders_add") ? true : false);
				instance._orders = orders;
				_instance._ordersPicking = page == "orders_add";
				_instance._why = page == "why";
				_instance._shown = "";
			}
		}

		public static void Search(string text)
		{
			if ((Object)(object)_instance?._search != (Object)null)
			{
				_instance._search.text = text;
			}
		}

		private void ClearSearch()
		{
			_ordersSearch = "";
			if ((Object)(object)_search != (Object)null && _search.text.Length > 0)
			{
				_search.text = "";
			}
		}

		private bool Matches(OrderPicks.Pick p)
		{
			string text = _ordersSearch.Trim();
			if (text.Length != 0 && OrderPicks.PickLabel(p).IndexOf(text, StringComparison.OrdinalIgnoreCase) < 0)
			{
				return p.Item.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		public static void ShowEnhancements()
		{
			if (!((Object)(object)_instance == (Object)null))
			{
				_instance._enh = true;
				_instance._shown = "";
			}
		}

		public static void Close(string reason)
		{
			if (IsOpen)
			{
				((Component)_instance).gameObject.SetActive(false);
				GUIManager.BlockInput(false);
				VfhLog.D(LogCat.UI, "orders.close", ("reason", reason));
				if ((Object)(object)_instance._hireling != (Object)null)
				{
					_instance._hireling.HoldForPanel(hold: false);
				}
				_instance._hireling = null;
			}
		}

		private static HirelingPanel Create()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 520f, 420f, false);
			((Object)val).name = "VFH_HirelingPanel";
			HirelingPanel panel = val.AddComponent<HirelingPanel>();
			panel._content = PanelUi.Fill(val.transform, "content");
			ref RectTransform? close = ref panel._close;
			Transform transform = ((Component)PanelUi.Button(val.transform, "$vfh_close", 200f, -30f, 80f, 34f, delegate
			{
				Close("button");
			})).transform;
			close = (RectTransform?)(object)((transform is RectTransform) ? transform : null);
			GameObject val2 = GUIManager.Instance.CreateInputField(val.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -92f), (ContentType)0, Localization.instance.Localize("$vfh_orders_search"), 16, 360f, 32f);
			panel._search = val2.GetComponent<InputField>();
			((UnityEvent<string>)(object)panel._search.onValueChanged).AddListener((UnityAction<string>)delegate(string v)
			{
				panel._ordersSearch = v;
				panel._ordersPage = 0;
				panel._nextRefresh = 0f;
			});
			val2.SetActive(false);
			val.SetActive(false);
			PanelUi.Clicked += delegate
			{
				if ((Object)(object)_instance != (Object)null)
				{
					_instance._nextRefresh = 0f;
				}
			};
			return panel;
		}

		private void Update()
		{
			//IL_003b: 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)
			Hireling hireling = _hireling;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)hireling == (Object)null || hireling.Zdo == null || (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || Vector3.Distance(((Component)localPlayer).transform.position, ((Component)hireling).transform.position) > 8f || ZInput.GetKeyDown((KeyCode)27, true))
			{
				Close(((Object)(object)hireling == (Object)null) ? "gone" : "walked away");
				return;
			}
			if (Time.unscaledTime >= _nextHold)
			{
				_nextHold = Time.unscaledTime + 1f;
				hireling.HoldForPanel(hold: true);
			}
			if (Time.unscaledTime < _nextRefresh)
			{
				return;
			}
			_nextRefresh = Time.unscaledTime + 0.3f;
			object obj = hireling.Mode;
			object obj2 = hireling.FollowMode;
			object obj3 = hireling.Stance;
			object obj4 = hireling.HasPost;
			object obj5 = _all;
			object displayName = hireling.DisplayName;
			object obj6 = hireling.Zdo.GetString("vfh_skip_items", "");
			object obj7 = hireling.WorksAtHome;
			object obj8 = hireling.IsParked;
			object obj9 = hireling.Level;
			bool flag = ChoreRules.ChoresFor(hireling.Job).Count > 0;
			if (!flag)
			{
				JobType job = hireling.Job;
				bool flag2 = (uint)job <= 1u;
				flag = flag2;
			}
			string text = string.Format("{0}|{1}|{2}|{3}|{4}|{5}|{6}|{7}|{8}|{9}|{10}", obj, obj2, obj3, obj4, obj5, displayName, obj6, obj7, obj8, obj9, flag ? (hireling.Zdo.GetString("vfh_activity", "") + "|" + hireling.Zdo.GetString("vfh_why", "")) : "");
			if (_orders)
			{
				HiringBoard ob = BoardOrders.BoardOf(hireling.BoardId);
				if (ob != null)
				{
					OrderList orderList = BoardOrders.For(ob);
					Stock os = BoardOrders.Stock(ob);
					text = text + $"|orders|{_ordersPicking}|{_ordersPage}|{_ordersSearch}|{orderList.Serialize()}|" + string.Join(",", from o in OrderPicks.For(orderList, hireling.Job)
						select OrderPicks.Have(ob, os, o));
				}
			}
			if (_why)
			{
				text += string.Format("|why|{0}|{1}", _whyPage, hireling.Zdo.GetString("vfh_why", ""));
				HiringBoard hiringBoard = BoardOrders.BoardOf(hireling.BoardId);
				if (hiringBoard != null)
				{
					Stock ws = BoardOrders.Stock(hiringBoard);
					text = text + "|" + string.Join(",", from o in WhyOrders(hireling, hiringBoard)
						select $"{o.Item}:{o.Target}:{o.Paused}:{ws.Have(o.Item)}");
				}
			}
			text = ((!_enh) ? (text + "|" + hireling.Zdo.GetString("vfh_enh", "")) : (text + string.Format("|enh|{0}|{1}{2}|{3}", hireling.Zdo.GetString("vfh_enh", ""), _pendingLevel, _pendingChoice, VfhConfig.Enhancements.Value)));
			if (!(text == _shown))
			{
				_shown = text;
				Build(hireling);
			}
		}

		private void Build(Hireling h)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b3e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b49: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d34: Unknown result type (might be due to invalid IL or missing references)
			//IL_0d51: Unknown result type (might be due to invalid IL or missing references)
			//IL_07f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_08c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c9e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c92: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a9a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0acd: Unknown result type (might be due to invalid IL or missing references)
			PanelUi.Clear((Transform)(object)_content);
			Transform content = (Transform)(object)_content;
			InputField? search = _search;
			if (search != null)
			{
				((Component)search).gameObject.SetActive(_orders && _ordersPicking);
			}
			Transform transform = ((Component)this).transform;
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if (val != null)
			{
				val.sizeDelta = new Vector2((_enh || _orders) ? 760f : (_why ? 660f : 520f), val.sizeDelta.y);
				if ((Object)(object)_close != (Object)null)
				{
					_close.anchoredPosition = new Vector2(val.sizeDelta.x / 2f - 60f, _close.anchoredPosition.y);
				}
			}
			if (_enh)
			{
				BuildEnhancements(h);
				return;
			}
			if (_orders)
			{
				BuildOrders(h);
				return;
			}
			if (_why)
			{
				BuildWhy(h);
				return;
			}
			bool flag = h.Mode == HirelingMode.Following;
			PanelUi.Button(content, "$vfh_orders_rename", -190f, -45f, 90f, 30f, delegate
			{
				Rename(h);
			});
			PanelUi.Text(content, $"{h.DisplayName} — $vfh_job_{h.Job.ToString().ToLowerInvariant()} $vfh_level {h.Level}", 15f, -45f, 290f, 22, (TextAnchor)4, null, bold: true);
			float num = -100f;
			if (flag)
			{
				PanelUi.Text(content, "$vfh_orders_mode", -170f, num, 140f, 18, (TextAnchor)3);
				FollowMode[] array = new FollowMode[3]
				{
					FollowMode.Follow,
					FollowMode.Stay,
					FollowMode.GatherHere
				};
				for (int num2 = 0; num2 < array.Length; num2++)
				{
					FollowMode m = array[num2];
					Highlight(PanelUi.Button(content, "$vfh_mode_" + m.ToString().ToLowerInvariant(), -40f + (float)num2 * 110f, num, 104f, 34f, delegate
					{
						SetMode(m);
					}), h.FollowMode == m);
				}
				num -= 50f;
			}
			PanelUi.Text(content, "$vfh_orders_stance", -170f, num, 140f, 18, (TextAnchor)3);
			IReadOnlyList<Stance> readOnlyList = StanceRules.Allowed(h.Job, h.Enh.Has(EnhancementId.Watchman));
			for (int num3 = 0; num3 < readOnlyList.Count; num3++)
			{
				Stance s = readOnlyList[num3];
				Highlight(PanelUi.Button(content, "$vfh_stance_" + s.ToString().ToLowerInvariant(), -40f + (float)num3 * 110f, num, 104f, 34f, delegate
				{
					SetStance(s);
				}), h.Stance == s);
			}
			num -= 50f;
			if (VfhConfig.Enhancements.Value && h.BoardId.Length > 0)
			{
				ZDO? zdo = h.Zdo;
				int count = EnhancementRules.Owed(EnhancementPicks.Parse((zdo != null) ? zdo.GetString("vfh_enh", "") : null), h.Level).Count;
				Highlight(PanelUi.Button(content, (count > 0) ? Localization.instance.Localize("$vfh_enh_open", new string[1] { count.ToString() }) : "$vfh_enh_open_none", 0f, num, 300f, 32f, delegate
				{
					_enh = true;
					_pendingLevel = 0;
					_shown = "";
				}), count > 0);
				num -= 50f;
			}
			JobType job = h.Job;
			bool flag2 = (uint)job <= 1u;
			if (flag2 && DataStore.Current.Jobs.TryGetValue(h.Job, out JobData value) && value.GatherToggles.Count > 0)
			{
				PanelUi.Text(content, "$vfh_orders_gather", -170f, num, 140f, 18, (TextAnchor)3);
				HashSet<string> skipItems = h.SkipItems;
				for (int num4 = 0; num4 < value.GatherToggles.Count; num4++)
				{
					string item = value.GatherToggles[num4];
					bool flag3 = !skipItems.Contains(item);
					string text = Localization.instance.Localize(ItemName(item)) + ": " + Localization.instance.Localize(flag3 ? "$vfh_on" : "$vfh_off");
					ShowToggle(PanelUi.Button(content, text, -5f + (float)(num4 % 2) * 170f, num - (float)(num4 / 2) * 40f, 164f, 34f, delegate
					{
						ToggleItem(item);
					}), flag3);
				}
				num -= (float)((value.GatherToggles.Count + 1) / 2) * 40f + 10f;
				ShowToggle(PanelUi.Button(content, h.WorksAtHome ? "$vfh_orders_home_work_on" : "$vfh_orders_home_work_off", 0f, num, 360f, 34f, ToggleHome), h.WorksAtHome);
				num -= 44f;
				PanelUi.Button(content, Localization.instance.Localize("$vfh_why_open", new string[1] { WhyLines(h).Count.ToString() }), 0f, num, 300f, 32f, OpenWhy);
				num -= 50f;
			}
			if (ChoreRules.ChoresFor(h.Job).Count > 0 && DataStore.Current.Jobs.TryGetValue(h.Job, out JobData value2))
			{
				PanelUi.Text(content, "$vfh_orders_chores", -170f, num, 140f, 18, (TextAnchor)3);
				ZDO? zdo2 = h.Zdo;
				HashSet<ChoreKind> hashSet = ChoreRules.ChoresOff((zdo2 != null) ? zdo2.GetString("vfh_skip_items", "") : null);
				num -= 30f;
				foreach (ChoreKind kind in ChoreRules.ChoresFor(h.Job))
				{
					string text2 = Localization.instance.Localize("$vfh_chore_" + ChoreKeys.Key(kind));
					string text3 = LockedState(kind, value2, h.Level, h.BoardId);
					if (text3 != null)
					{
						PanelUi.Text(content, text2 + ": " + text3, 0f, num, 400f, 15, (TextAnchor)4, PanelUi.Dim);
						num -= 30f;
						continue;
					}
					bool flag4 = !hashSet.Contains(kind);
					ShowToggle(PanelUi.Button(content, text2 + ": " + Localization.instance.Localize(flag4 ? "$vfh_chore_state_on" : "$vfh_chore_state_off"), 0f, num, 400f, 30f, delegate
					{
						ToggleChore(kind);
					}), flag4);
					num -= 34f;
					string text4 = StillLocked(kind, value2, h.Level);
					if (text4.Length > 0)
					{
						PanelUi.Text(content, text4, 0f, num + 4f, 400f, 13, (TextAnchor)4, PanelUi.Dim);
						num -= 22f;
					}
				}
				int count2 = WhyLines(h).Count;
				if (OrderPicks.TakesOrders(h.Job))
				{
					int count3 = OrderPicks.For(BoardOrders.For(BoardOrders.BoardOf(h.BoardId)?.Zdo), h.Job).Count;
					PanelUi.Button(content, Localization.instance.Localize("$vfh_orders_open", new string[1] { count3.ToString() }), -105f, num - 6f, 200f, 32f, delegate
					{
						_orders = true;
						_ordersPicking = false;
						_ordersPage = 0;
						_shown = "";
					});
					PanelUi.Button(content, Localization.instance.Localize("$vfh_why_open", new string[1] { count2.ToString() }), 105f, num - 6f, 200f, 32f, OpenWhy);
				}
				else
				{
					PanelUi.Button(content, Localization.instance.Localize("$vfh_why_open", new string[1] { count2.ToString() }), 0f, num - 6f, 300f, 32f, OpenWhy);
				}
				num -= 44f;
				num -= 10f;
				ZDO? zdo3 = h.Zdo;
				string text5 = ActivityText.Show(((zdo3 != null) ? zdo3.GetString("vfh_activity", "") : null) ?? "");
				if (text5.Length > 0)
				{
					Text obj = PanelUi.Text(content, text5, 0f, num - 8f, 440f, 15, (TextAnchor)4, PanelUi.Dim);
					obj.horizontalOverflow = (HorizontalWrapMode)0;
					Transform transform2 = ((Component)obj).transform;
					RectTransform val2 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null);
					if (val2 != null)
					{
						val2.sizeDelta = new Vector2(440f, 40f);
					}
					num -= 52f;
				}
			}
			if (flag)
			{
				Highlight(PanelUi.Button(content, _all ? "$vfh_orders_all_on" : "$vfh_orders_all_off", 0f, num, 360f, 34f, delegate
				{
					_all = !_all;
					_shown = "";
				}), _all);
				num -= 55f;
				if (Utils.DistanceXZ(((Component)h).transform.position, h.Home) <= h.Radius)
				{
					PanelUi.Button(content, "$vfh_orders_release", 0f, num, 240f, 38f, delegate
					{
						Act(FollowerServer.Kind.Release);
					});
				}
				else
				{
					Inventory? cargoInventory = h.CargoInventory;
					List<string> list = ((cargoInventory != null) ? (from i in cargoInventory.GetAllItems().Where(HomeReturn.LeavesBehind)
						select Localization.instance.Localize(i.m_shared.m_name)).Distinct().ToList() : null) ?? new List<string>();
					PanelUi.Button(content, (list.Count > 0) ? "$vfh_orders_send_home_drop" : "$vfh_orders_send_home", 0f, num, 300f, 38f, delegate
					{
						Act(FollowerServer.Kind.SendHome);
					});
					PanelUi.Text(content, (list.Count > 0) ? Localization.instance.Localize("$vfh_orders_send_home_drop_hint", new string[1] { string.Join(", ", list) }) : "$vfh_orders_send_home_hint", 0f, num - 35f, 440f, 15, (TextAnchor)4, (list.Count > 0) ? GUIManager.Instance.ValheimOrange : PanelUi.Dim);
				}
			}
			else if (h.IsParked)
			{
				PanelUi.Button(content, "$vfh_roster_back_to_work", 0f, num, 240f, 38f, delegate
				{
					BoardContracts.Park(h.Hid, park: false);
				});
			}
			else if (h.HasPost)
			{
				PanelUi.Button(content, "$vfh_orders_clear_post", 0f, num, 240f, 38f, delegate
				{
					Act(FollowerServer.Kind.ClearPost);
				});
			}
			Transform transform3 = ((Component)this).transform;
			RectTransform val3 = (RectTransform)(object)((transform3 is RectTransform) ? transform3 : null);
			if (val3 != null)
			{
				val3.sizeDelta = new Vector2(val3.sizeDelta.x, Mathf.Max(420f, 0f - num + 70f));
			}
		}

		private void BuildEnhancements(Hireling h)
		{
			//IL_00c1: 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_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			Transform content = (Transform)(object)_content;
			PanelUi.Button(content, "$vfh_orders_back", -320f, -45f, 100f, 30f, delegate
			{
				_enh = false;
				_pendingLevel = 0;
				_shown = "";
			});
			PanelUi.Text(content, Localization.instance.Localize("$vfh_enh_title", new string[1] { h.DisplayName }), -10f, -45f, 420f, 22, (TextAnchor)4, null, bold: true);
			float num = -85f;
			if (!VfhConfig.Enhancements.Value)
			{
				PanelUi.Text(content, "$vfh_enh_off", 0f, num, 600f, 16, (TextAnchor)4, PanelUi.Dim);
				return;
			}
			PanelUi.Text(content, "$vfh_enh_hint", 0f, num, 660f, 14, (TextAnchor)4, PanelUi.Dim);
			num -= 45f;
			ZDO? zdo = h.Zdo;
			EnhancementPicks enhancementPicks = EnhancementPicks.Parse((zdo != null) ? zdo.GetString("vfh_enh", "") : null);
			for (int num2 = 2; num2 <= 8; num2++)
			{
				char c = enhancementPicks.Get(num2);
				Color value = ((num2 > h.Level) ? PanelUi.Dim : ((c == '-') ? GUIManager.Instance.ValheimOrange : GUIManager.Instance.ValheimBeige));
				PanelUi.Text(content, Localization.instance.Localize("$vfh_enh_level", new string[1] { num2.ToString() }), -330f, num, 80f, 16, (TextAnchor)3, value, bold: true);
				var (id, id2) = EnhancementCatalog.Pair(h.Job, num2);
				Option(h, num2, 'A', id, -125f, num, c);
				Option(h, num2, 'B', id2, 200f, num, c);
				num -= 74f;
			}
			Transform transform = ((Component)this).transform;
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if (val != null)
			{
				val.sizeDelta = new Vector2(val.sizeDelta.x, Mathf.Max(420f, 0f - num + 40f));
			}
		}

		private void Option(Hireling h, int level, char choice, EnhancementId id, float x, float y, char chosen)
		{
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			Transform content = (Transform)(object)_content;
			string text = Localization.instance.Localize(EnhancementText.NameKey(h.Job, id));
			string text2 = Localization.instance.Localize(EnhancementText.DescKey(h.Job, id), EnhancementText.Args(DataStore.Current, h.Job, id));
			bool flag = level > h.Level;
			bool flag2 = _pendingLevel == level && _pendingChoice == choice;
			string text3 = (flag2 ? Localization.instance.Localize("$vfh_enh_confirm", new string[1] { text }) : ((chosen == choice) ? ("✓ " + text) : text));
			Button val = PanelUi.Button(content, text3, x, y, 310f, 30f, delegate
			{
				ClickOption(h, level, choice);
			});
			if (chosen == choice)
			{
				Highlight(val, on: true);
			}
			else if (chosen != '-' || flag)
			{
				((Selectable)val).interactable = false;
			}
			else if (flag2)
			{
				Highlight(val, on: true);
			}
			((Graphic)PanelUi.Text(content, text2, x, y - 33f, 310f, 12, (TextAnchor)1, (chosen == choice) ? GUIManager.Instance.ValheimBeige : PanelUi.Dim)).rectTransform.SetSizeWithCurrentAnchors((Axis)1, 32f);
		}

		private void ClickOption(Hireling h, int level, char choice)
		{
			if (_pendingLevel == level && _pendingChoice == choice)
			{
				_pendingLevel = 0;
				BoardContracts.ChooseEnhancement(h.BoardId, h.Hid, level, choice);
				VfhLog.I(LogCat.UI, "enh.choose", ("hid", h.Hid), ("level", level), ("choice", choice));
			}
			else
			{
				_pendingLevel = level;
				_pendingChoice = choice;
			}
			_shown = "";
		}

		private void BuildOrders(Hireling h)
		{
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0543: Unknown result type (might be due to invalid IL or missing references)
			//IL_0585: Unknown result type (might be due to invalid IL or missing references)
			//IL_060c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0605: Unknown result type (might be due to invalid IL or missing references)
			//IL_05fe: Unknown result type (might be due to invalid IL or missing references)
			Transform content = (Transform)(object)_content;
			PanelUi.Button(content, "$vfh_orders_back", -310f, -45f, 100f, 30f, delegate
			{
				if (_ordersPicking)
				{
					_ordersPicking = false;
				}
				else
				{
					_orders = false;
				}
				_shown = "";
			});
			PanelUi.Text(content, Localization.instance.Localize(_ordersPicking ? "$vfh_orders_pick_title" : "$vfh_orders_title", new string[1] { h.DisplayName }), 30f, -45f, 480f, 22, (TextAnchor)4, null, bold: true);
			float num = -85f;
			HiringBoard board = BoardOrders.BoardOf(h.BoardId);
			if ((Object)(object)board == (Object)null)
			{
				PanelUi.Text(content, "$vfh_orders_no_board", 0f, num, 600f, 16, (TextAnchor)4, PanelUi.Dim);
				Fit(0f - num + 60f);
				return;
			}
			bool flag = PrivateArea.CheckAccess(((Component)board).transform.position, 0f, false, false);
			OrderList list = BoardOrders.For(board);
			if (_ordersPicking)
			{
				num -= 52f;
				List<OrderPicks.Pick> list2 = (from p in OrderPicks.Picks(h.Job)
					where list.Find(p.Item) == null && Matches(p)
					select p).ToList();
				int num2 = Mathf.Max(1, (list2.Count + 14 - 1) / 14);
				_ordersPage = Mathf.Clamp(_ordersPage, 0, num2 - 1);
				int num3 = 0;
				foreach (OrderPicks.Pick item2 in list2.Skip(_ordersPage * 14).Take(14))
				{
					float x = ((num3 % 2 == 0) ? (-180f) : 180f);
					float num4 = num - (float)(num3 / 2) * 48f;
					bool flag2 = h.Level >= item2.Level;
					OrderPicks.Pick chosen = item2;
					((Selectable)PanelUi.Button(content, OrderPicks.PickLabel(item2), x, num4, 340f, 30f, delegate
					{
						BoardOrders.Submit(board, OrderEdit.Add, chosen.Item, chosen.Kind, OrderPicks.StartTarget(chosen.Kind));
						_ordersPicking = false;
						_ordersPage = 0;
						ClearSearch();
						_shown = "";
					})).interactable = flag;
					PanelUi.Text(content, Localization.instance.Localize(flag2 ? "$vfh_orders_level" : "$vfh_orders_needs_level", new string[1] { item2.Level.ToString() }), x, num4 - 20f, 340f, 12, (TextAnchor)4, flag2 ? PanelUi.Dim : PanelUi.Bad);
					num3++;
				}
				if (list2.Count == 0)
				{
					PanelUi.Text(content, (_ordersSearch.Trim().Length > 0) ? Localization.instance.Localize("$vfh_orders_search_none", new string[1] { _ordersSearch.Trim() }) : "$vfh_orders_pick_none", 0f, num, 600f, 16, (TextAnchor)4, PanelUi.Dim);
				}
				num -= (float)Mathf.Max(1, (num3 + 1) / 2) * 48f + 6f;
				num = OrdersPager(content, num, num2);
				Fit(0f - num + 50f);
				return;
			}
			PanelUi.Text(content, "$vfh_orders_hint", 0f, num, 700f, 14, (TextAnchor)4, PanelUi.Dim);
			num -= 38f;
			Stock stock = BoardOrders.Stock(board);
			List<ProductionOrder> list3 = OrderPicks.For(list, h.Job);
			int num5 = Mathf.Max(1, (list3.Count + 10 - 1) / 10);
			_ordersPage = Mathf.Clamp(_ordersPage, 0, num5 - 1);
			if (list3.Count == 0)
			{
				PanelUi.Text(content, "$vfh_orders_none", 0f, num, 600f, 16, (TextAnchor)4, PanelUi.Dim);
				num -= 36f;
			}
			List<Container> chests = ((h.Job == JobType.Smelter) ? ChestModes.Stock(ChestFinder.Find(h.WorkCentre, h.Radius)).ToList() : new List<Container>());
			foreach (ProductionOrder o in list3.Skip(_ordersPage * 10).Take(10))
			{
				int value;
				int have = ((o.Kind == OrderKind.Station) ? (StewardLimits.Held(chests, o.Item) + (stock.Piled.TryGetValue(o.Item, out value) ? value : 0)) : OrderPicks.Have(board, stock, o));
				bool flag3 = o.Item == "*";
				Sprite val = OrderPicks.Icon(o.Item);
				if (val != null)
				{
					PanelUi.Icon(content, val, -345f, num, 32f);
				}
				PanelUi.Text(content, OrderPicks.Name(o.Item), -195f, num + 8f, 240f, 16, (TextAnchor)3, o.Paused ? new Color?(PanelUi.Dim) : ((Color?)null));
				PanelUi.Text(content, flag3 ? "$vfh_orders_everything_hint" : OrderPicks.KindLabel(o.Kind), -195f, num - 10f, 240f, 12, (TextAnchor)3, PanelUi.Dim);
				PanelUi.Text(content, o.Paused ? Localization.instance.Localize("$vfh_limits_paused") : OrderPicks.Progress(o, have), 15f, num, 120f, 16, (TextAnchor)4, (o.Paused || o.IsInfinite) ? PanelUi.Dim : (OrderPicks.Met(o, have) ? PanelUi.Good : PanelUi.Bad));
				string item = o.Item;
				List<Button> list4 = new List<Button>();
				if (!flag3)
				{
					Button obj = PanelUi.Button(content, "-", 68f, num, 30f, 30f, delegate
					{
						BoardOrders.Submit(board, OrderEdit.Target, item, OrderKind.Crop, o.Target - OrderStep());
					});
					Button val2 = PanelUi.Button(content, "+", 102f, num, 30f, 30f, delegate
					{
						BoardOrders.Submit(board, OrderEdit.Target, item, OrderKind.Crop, o.Target + OrderStep());
					});
					bool interactable = (((Selectable)val2).interactable = flag && !o.IsInfinite);
					((Selectable)obj).interactable = interactable;
					int back = ((o.Kind == OrderKind.Station) ? 100 : OrderPicks.StartTarget(o.Kind));
					Button val3 = PanelUi.Button(content, "∞", 140f, num, 34f, 30f, delegate
					{
						BoardOrders.Submit(board, OrderEdit.Target, item, OrderKind.Crop, o.IsInfinite ? back : int.MaxValue);
					});
					Highlight(val3, o.IsInfinite);
					list4.Add(val3);
					list4.Add(PanelUi.Button(content, "^", 180f, num, 30f, 30f, delegate
					{
						BoardOrders.Submit(board, OrderEdit.Up, item);
					}));
					list4.Add(PanelUi.Button(content, "v", 214f, num, 30f, 30f, delegate
					{
						BoardOrders.Submit(board, OrderEdit.Down, item);
					}));
				}
				list4.Add(PanelUi.Button(content, o.Paused ? "$vfh_orders_resume" : "$vfh_orders_pause", 278f, num, 90f, 30f, delegate
				{
					BoardOrders.Submit(board, OrderEdit.Pause, item, OrderKind.Crop, 0, !o.Paused);
				}));
				list4.Add(PanelUi.Button(content, "X", 345f, num, 30f, 30f, delegate
				{
					BoardOrders.Submit(board, OrderEdit.Remove, item);
				}));
				foreach (Button item3 in list4)
				{
					((Selectable)item3).interactable = flag;
				}
				num -= 44f;
			}
			num = OrdersPager(content, num, num5);
			num -= 6f;
			((Selectable)PanelUi.Button(content, "$vfh_orders_add", 0f, num, 260f, 34f, delegate
			{
				_ordersPicking = true;
				_ordersPage = 0;
				ClearSearch();
				_shown = "";
			})).interactable = flag;
			num -= 40f;
			Fit(0f - num + 50f);
		}

		private float OrdersPager(Transform t, float y, int pages)
		{
			if (pages <= 1)
			{
				return y;
			}
			PanelUi.Button(t, "<", -60f, y, 40f, 30f, delegate
			{
				_ordersPage = Mathf.Max(0, _ordersPage - 1);
				_shown = "";
			});
			PanelUi.Text(t, $"{_ordersPage + 1} / {pages}", 0f, y, 70f, 16, (TextAnchor)4);
			PanelUi.Button(t, ">", 60f, y, 40f, 30f, delegate
			{
				_ordersPage = Mathf.Min(pages - 1, _ordersPage + 1);
				_shown = "";
			});
			return y - 40f;
		}

		private static int OrderStep()
		{
			if (!Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303))
			{
				return 5;
			}
			return 1;
		}

		private void OpenWhy()
		{
			_why = true;
			_whyPage = 0;
			_shown = "";
		}

		private static List<(string Item, string Why)> WhyLines(Hireling h)
		{
			ZDO? zdo = h.Zdo;
			return (from l in (((zdo != null) ? zdo.GetString("vfh_why", "") : null) ?? "").Split(new char[1] { '\n' })
				where l.Length > 0
				select l).Select(delegate(string l)
			{
				int num = l.IndexOf('\t');
				return (num >= 0) ? (l.Substring(0, num), l.Substring(num + 1)) : ("", l);
			}).ToList();
		}

		private static List<ProductionOrder> WhyOrders(Hireling h, HiringBoard board)
		{
			return OrderPicks.For(BoardOrders.For(board), h.Job);
		}

		private void BuildWhy(Hireling h)
		{
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0548: Unknown result type (might be due to invalid IL or missing references)
			//IL_0589: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0351: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_0334: Unknown result type (might be due to invalid IL or missing references)
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			Transform content = (Transform)(object)_content;
			PanelUi.Button(content, "$vfh_orders_back", -250f, -45f, 100f, 30f, delegate
			{
				_why = false;
				_shown = "";
			});
			PanelUi.Text(content, Localization.instance.Localize("$vfh_why_title", new string[1] { h.DisplayName }), 20f, -45f, 380f, 22, (TextAnchor)4, null, bold: true);
			float num = -90f;
			List<(string, string)> source = WhyLines(h);
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			foreach (var item3 in source.Where<(string, string)>(((string Item, string Why) l) => l.Item.Length > 0))
			{
				string item = item3.Item1;
				string item2 = item3.Item2;
				dictionary[item] = item2;
			}
			HiringBoard hiringBoard = BoardOrders.BoardOf(h.BoardId);
			if (OrderPicks.TakesOrders(h.Job))
			{
				PanelUi.Text(content, "$vfh_why_orders", 0f, num, 560f, 17, (TextAnchor)4, null, bold: true);
				num -= 34f;
				List<ProductionOrder> list = (((Object)(object)hiringBoard != (Object)null) ? WhyOrders(h, hiringBoard) : new List<ProductionOrder>());
				if (list.Count == 0)
				{
					PanelUi.Text(content, ((Object)(object)hiringBoard == (Object)null) ? "$vfh_limits_no_board" : "$vfh_why_no_orders", 0f, num, 560f, 15, (TextAnchor)4, PanelUi.Dim);
					num -= 32f;
				}
				int pages = Mathf.Max(1, (list.Count + 10 - 1) / 10);
				_whyPage = Mathf.Clamp(_whyPage, 0, pages - 1);
				Stock stock = (((Object)(object)hiringBoard != (Object)null) ? BoardOrders.Stock(hiringBoard) : null);
				foreach (ProductionOrder item4 in list.Skip(_whyPage * 10).Take(10))
				{
					int value;
					int have = ((item4.Kind != OrderKind.Herd) ? stock.Have(item4.Item) : (RanchState.For(hiringBoard).Adults.TryGetValue(item4.Item, out value) ? value : 0));
					Sprite val = OrderPicks.Icon(item4.Item);
					if (val != null)
					{
						PanelUi.Icon(content, val, -295f, num, 28f);
					}
					PanelUi.Text(content, OrderPicks.Name(item4.Item), -195f, num, 170f, 15, (TextAnchor)3, item4.Paused ? new Color?(PanelUi.Dim) : ((Color?)null));
					PanelUi.Text(content, OrderPicks.Progress(item4, have), -75f, num, 80f, 15, (TextAnchor)4, OrderPicks.Met(item4, have) ? PanelUi.Good : PanelUi.Dim);
					Color value3;
					string text2;
					if (!item4.Paused)
					{
						if (!OrderPicks.Met(item4, have))
						{
							if (!dictionary.TryGetValue(item4.Item, out var value2))
							{
								string text = Localization.instance.Localize("$vfh_why_on_it");
								Color good = PanelUi.Good;
								value3 = good;
								text2 = text;
							}
							else
							{
								string text3 = ActivityText.Show(value2);
								Color good = PanelUi.Bad;
								value3 = good;
								text2 = text3;
							}
						}
						else
						{
							string text4 = Localization.instance.Localize("$vfh_why_done");
							Color good = PanelUi.Good;
							value3 = good;
							text2 = text4;
						}
					}
					else
					{
						string text5 = Localization.instance.Localize("$vfh_limits_paused");
						Color good = PanelUi.Dim;
						value3 = good;
						text2 = text5;
					}
					PanelUi.Text(content, text2, 155f, num, 340f, 13, (TextAnchor)3, value3);
					num -= 34f;
				}
				if (pages > 1)
				{
					PanelUi.Button(content, "<", -60f, num, 40f, 30f, delegate
					{
						_whyPage = Mathf.Max(0, _whyPage - 1);
						_shown = "";
					});
					PanelUi.Text(content, $"{_whyPage + 1} / {pages}", 0f, num, 70f, 16, (TextAnchor)4);
					PanelUi.Button(content, ">", 60f, num, 40f, 30f, delegate
					{
						_whyPage = Mathf.Min(pages - 1, _whyPage + 1);
						_shown = "";
					});
					num -= 40f;
				}
				num -= 10f;
			}
			Transform parent = content;
			JobType job = h.Job;
			bool flag = (uint)job <= 1u;
			PanelUi.Text(parent, flag ? "$vfh_why_found" : "$vfh_why_other", 0f, num, 560f, 17, (TextAnchor)4, null, bold: true);
			num -= 32f;
			List<string> list2 = (from l in source
				where l.Item.Length == 0
				select l.Why).ToList();
			if (list2.Count == 0)
			{
				PanelUi.Text(content, "$vfh_why_none", 0f, num, 560f, 15, (TextAnchor)4, PanelUi.Dim);
				num -= 30f;
			}
			foreach (string item5 in list2)
			{
				PanelUi.Text(content, ActivityText.Show(item5), 0f, num, 600f, 14, (TextAnchor)4, PanelUi.Bad);
				num -= 28f;
			}
			Fit(0f - num + 50f);
		}

		private void Fit(float height)
		{
			//IL_0011: 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)
			Transform transform = ((Component)this).transform;
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			if (val != null)
			{
				val.sizeDelta = new Vector2(val.sizeDelta.x, Mathf.Max(420f, height));
			}
		}

		private static string ItemName(string prefab)
		{
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(prefab) : null);
			ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				return val2.m_itemData.m_shared.m_name;
			}
			ZNetScene instance = ZNetScene.instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				GameObject prefab2 = instance.GetPrefab(prefab);
				obj = ((prefab2 != null) ? prefab2.GetComponent<Character>() : null);
			}
			Character val3 = (Character)obj;
			if (val3 == null)
			{
				return prefab;
			}
			return val3.m_name;
		}

		private void ToggleItem(string item)
		{
			Hireling h = _hireling;
			bool flag = !h.SkipItems.Contains(item);
			foreach (Hireling item2 in from f in Targets()
				where f.Job == h.Job
				select f)
			{
				HashSet<string> hashSet = new HashSet<string>(item2.SkipItems);
				if (flag)
				{
					hashSet.Add(item);
				}
				else
				{
					hashSet.Remove(item);
				}
				SubmitGather(item2, hashSet, !item2.WorksAtHome);
			}
		}

		private static string? LockedState(ChoreKind kind, JobData steward, int level, string boardId)
		{
			if (!ChoreLoop.ServerAllows(kind))
			{
				return Localization.instance.Localize("$vfh_chore_state_disabled");
			}
			if (kind == ChoreKind.Animals && ChoreLoop.RancherOnBoard(boardId))
			{
				return Localization.instance.Localize("$vfh_chore_state_rancher");
			}
			string text = StewardCompat.HandledBy(kind);
			if (text != null)
			{
				return Localization.instance.Localize("$vfh_chore_state_handled", new string[1] { text });
			}
			int num = ChoreRules.FirstUnlock(steward, kind);
			if (num == int.MaxValue)
			{
				return Localization.instance.Localize("$vfh_chore_state_disabled");
			}
			if (level >= num)
			{
				return null;
			}
			return Localization.instance.Localize("$vfh_chore_state_locked", new string[1] { num.ToString() });
		}

		private static string StillLocked(ChoreKind kind, JobData steward, int level)
		{
			if ((uint)(kind - 2) > 2u)
			{
				return "";
			}
			return string.Join(", ", from k in ChoreRules.GateKeys(steward, kind)
				where ChoreRules.MinLevel(steward, k) > level
				select StationName(k) + ": " + Localization.instance.Localize("$vfh_chore_state_locked", new string[1] { ChoreRules.MinLevel(steward, k).ToString() }));
		}

		private static string StationName(string prefab)
		{
			object obj;
			if (!((Object)(object)ZNetScene.instance != (Object)null))
			{
				obj = null;
			}
			else
			{
				GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab);
				obj = ((prefab2 != null) ? prefab2.GetComponent<Piece>() : null);
			}
			Piece val = (Piece)obj;
			if (!((Object)(object)val != (Object)null))
			{
				return prefab;
			}
			return Localization.instance.Localize(val.m_name);
		}

		private void ToggleChore(ChoreKind kind)
		{
			Hireling h = _hireling;
			ZDO? zdo = h.Zdo;
			bool flag = ChoreRules.ChoresOff((zdo != null) ? zdo.GetString("vfh_skip_items", "") : null).Contains(kind);
			foreach (Hireling item in from f in Targets()
				where f.Job == h.Job
				select f)
			{
				ZDO? zdo2 = item.Zdo;
				string skip = ChoreRules.WithChore((zdo2 != null) ? zdo2.GetString("vfh_skip_items", "") : null, kind, flag);
				SubmitGather(item, GatherRules.ParseSkip(skip), !item.WorksAtHome);
			}
			_shown = "";
		}

		private void ToggleHome()
		{
			Hireling h = _hireling;
			bool worksAtHome = h.WorksAtHome;
			foreach (Hireling item in from f in Targets()
				where f.Job == h.Job
				select f)
			{
				SubmitGather(item, item.SkipItems, worksAtHome);
			}
		}

		private static void SubmitGather(Hireling f, HashSet<string> skip, bool noHomeWork)
		{
			string text = GatherRules.FormatSkip(skip);
			if (f.BoardId.Length > 0)
			{
				MutationService.SubmitBoard(f.BoardId, new RosterOp
				{
					Type = RosterOpType.SetGather,
					Hid = f.Hid,
					SkipItems = text,
					NoHomeWork = noHomeWork
				});
			}
			else
			{
				MutationService.SubmitHireling(f.Hid, new HirelingOp
				{
					SkipItems = text,
					NoHomeWork = noHomeWork
				});
			}
			VfhLog.I(LogCat.UI, "hireling.gather_set", ("hid", f.Hid), ("skip", text), ("noHomeWork", noHomeWork));
		}

		private static void ShowToggle(Button b, bool on)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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)
			Text componentInChildren = ((Component)b).GetComponentInChildren<Text>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				((Graphic)componentInChildren).color = (Color)(on ? GUIManager.Instance.ValheimOrange : new Color(0.55f, 0.55f, 0.55f));
			}
			Graphic targetGraphic = ((Selectable)b).targetGraphic;
			Image val = (Image)(object)((targetGraphic is Image) ? targetGraphic : null);
			if (val != null)
			{
				((Graphic)val).color = (Color)(on ? Color.white : new Color(0.45f, 0.45f, 0.45f, 0.8f));
			}
		}

		private static void Highlight(Button b, bool on)
		{
			//IL_0025: 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)
			Text componentInChildren = ((Component)b).GetComponentInChildren<Text>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				((Graphic)componentInChildren).color = (on ? GUIManager.Instance.ValheimOrange : GUIManager.Instance.ValheimBeige);
			}
		}

		private IEnumerable<Hireling> Targets()
		{
			Hireling hireling = _hireling;
			if (!_all || hireling.Mode != HirelingMode.Following)
			{
				return new Hireling[1] { hireling };
			}
			return StoneInput.MyFollowers(Player.m_localPlayer, 30f).Append(hireling).Distinct();
		}

		private void SetMode(FollowMode mode)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			foreach (Hireling item in Targets())
			{
				Vector3 position = ((Component)item).transform.position;
				item.Ai.Order = null;
				MutationService.SubmitHireling(item.Hid, (mode == FollowMode.Follow) ? new HirelingOp
				{
					FollowMode = mode
				} : new HirelingOp
				{
					FollowMode = mode,
					StayPos = (position.x, position.y, position.z)
				});
				VfhLog.I(LogCat.Follow, "follow.mode", ("hid", item.Hid), ("mode", mode), ("via", "panel"));
			}
		}

		private void SetStance(Stance stance)
		{
			foreach (Hireling item in Targets())
			{
				if (StanceRules.IsAllowed(item.Job, stance, item.Enh.Has(EnhancementId.Watchman)) && item.BoardId.Length != 0)
				{
					MutationService.SubmitBoard(item.BoardId, new RosterOp
					{
						Type = RosterOpType.Edit,
						Hid = item.Hid,
						Radius = item.ContractRadius,
						Stance = stance
					});
					VfhLog.I(LogCat.Follow, "follow.stance", ("hid", item.Hid), ("stance", stance), ("via", "panel"));
				}
			}
		}

		private void Rename(Hireling h)
		{
			Close("rename");
			TextInput.instance.RequestText((TextReceiver)(object)new RenameReceiver(h), "$vfh_rename_topic", 24);
		}

		private void Act(FollowerServer.Kind kind)
		{
			Hireling hireling = _hireling;
			int quality = (from i in ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems().Where(CommandStoneItem.IsStone)
				select i.m_quality).DefaultIfEmpty(0).Max();
			FollowerServer.Send(kind, hireling.Hid, quality);
			Close("action");
		}
	}
	internal interface IBoardTab
	{
		string Title { get; }

		string Signature(HiringBoard board);

		void Build(RectTransform root, HiringBoard board);
	}
	internal static class OrderPicks
	{
		public sealed class Pick
		{
			public string Item = "";

			public OrderKind Kind;

			public int Level;
		}

		public static readonly JobType[] Jobs = new JobType[4]
		{
			JobType.Farmer,
			JobType.Cook,
			JobType.Rancher,
			JobType.Smelter
		};

		public static bool TakesOrders(JobType job)
		{
			switch (job)
			{
			case JobType.Smelter:
			case JobType.Farmer:
			case JobType.Cook:
			case JobType.Rancher:
				return true;
			default:
				return false;
			}
		}

		public static List<ProductionOrder> For(OrderList list, JobType job)
		{
			return job switch
			{
				JobType.Farmer => list.Orders.Where((ProductionOrder o) => o.Kind == OrderKind.Seed).Concat(list.Orders.Where((ProductionOrder o) => o.Kind == OrderKind.Crop)).ToList(), 
				JobType.Cook => list.Orders.Where((ProductionOrder o) => o.Kind == OrderKind.Kitchen).ToList(), 
				JobType.Rancher => list.Orders.Where((ProductionOrder o) => o.IsRanch).ToList(), 
				JobType.Smelter => list.Orders.Where((ProductionOrder o) => o.Kind == OrderKind.Station && o.Item != "*").Concat(list.Orders.Where((ProductionOrder o) => o.Kind == OrderKind.Station && o.Item == "*")).ToList(), 
				_ => new List<ProductionOrder>(), 
			};
		}

		public static int Have(HiringBoard board, Stock stock, ProductionOrder o)
		{
			if (o.Kind != OrderKind.Herd)
			{
				return stock.Have(o.Item);
			}
			return HerdHave(board, o.Item);
		}

		private static int HerdHave(HiringBoard board, string kind)
		{
			if (!RanchState.For(board).Adults.TryGetValue(kind, out var value))
			{
				return 0;
			}
			return value;
		}

		public static string KindLabel(OrderKind kind)
		{
			return kind switch
			{
				OrderKind.Seed => "$vfh_orders_kind_seed", 
				OrderKind.Crop => "$vfh_orders_kind_farm", 
				OrderKind.Meat => "$vfh_orders_kind_meat", 
				OrderKind.Egg => "$vfh_orders_kind_egg", 
				OrderKind.Herd => "$vfh_orders_kind_herd", 
				OrderKind.Station => "$vfh_orders_kind_steward", 
				_ => "$vfh_orders_kind_kitchen", 
			};
		}

		public static int StartTarget(OrderKind kind)
		{
			return kind switch
			{
				OrderKind.Seed => 10, 
				OrderKind.Meat => 40, 
				OrderKind.Herd => 4, 
				OrderKind.Station => int.MaxValue, 
				_ => 20, 
			};
		}

		public static string TargetText(int target)
		{
			if (target != int.MaxValue)
			{
				return target.ToString();
			}
			return "∞";
		}

		public static string Progress(ProductionOrder o, int have)
		{
			if (!(o.Item == "*"))
			{
				return $"{have} / {TargetText(o.Target)}";
			}
			return "∞";
		}

		public static bool Met(ProductionOrder o, int have)
		{
			if (!o.IsInfinite)
			{
				return have >= o.Target;
			}
			return false;
		}

		public static List<Pick> Picks(JobType job)
		{
			switch (job)
			{
			case JobType.Smelter:
			{
				JobData value;
				JobData steward = (DataStore.Current.Jobs.TryGetValue(JobType.Smelter, out value) ? value : new JobData());
				List<Pick> list2 = new List<Pick>();
				list2.Add(new Pick
				{
					Item = "*",
					Kind = OrderKind.Station,
					Level = 1
				});
				list2.AddRange(from p in StewardLimits.Products()
					select new Pick
					{
						Item = p.Item,
						Kind = OrderKind.Station,
						Level = ChoreRules.MinLevel(steward, p.Gate)
					});
				return list2;
			}
			case JobType.Rancher:
			{
				List<Pick> ranch = new List<Pick>();
				foreach (AnimalKind k in AnimalCatalog.Kinds)
				{
					ranch.Add(new Pick
					{
						Item = k.Prefab,
						Kind = OrderKind.Herd,
						Level = 1
					});
					foreach (string item in k.Meats.Keys.Where((string m) => ranch.All((Pick p) => p.Item != m)))
					{
						ranch.Add(new Pick
						{
							Item = item,
							Kind = OrderKind.Meat,
							Level = 1
						});
					}
					if (k.EggItem.Length > 0 && ranch.All((Pick p) => p.Item != k.EggItem))
					{
						ranch.Add(new Pick
						{
							Item = k.EggItem,
							Kind = OrderKind.Egg,
							Level = 1
						});
					}
				}
				return (from p in ranch
					orderby p.Kind, Name(p.Item)
					select p).ToList();
			}
			case JobType.Cook:
				return (from kitchenInfo in KitchenCatalog.All
					group kitchenInfo by kitchenInfo.Output into g
					select new Pick
					{
						Item = g.Key,
						Kind = OrderKind.Kitchen,
						Level = g.Min((KitchenInfo kitchenInfo) => kitchenInfo.Level)
					} into p
					orderby p.Level, Name(p.Item)
					select p).ToList();
			default:
			{
				List<CropInfo> list = CropCatalog.Infos.ToList();
				Dictionary<string, Pick> dictionary = new Dictionary<string, Pick>();
				foreach (CropInfo item2 in list)
				{
					AddPick(dictionary, item2.Yields, item2.Level, list);
					if (!item2.Regrowing)
					{
						AddPick(dictionary, item2.Consumes, item2.Level, list);
					}
				}
				return (from p in dictionary.Values
					orderby p.Level, p.Kind, Name(p.Item)
					select p).ToList();
			}
			}
		}

		private static void AddPick(Dictionary<string, Pick> picks, string item, int level, List<CropInfo> crops)
		{
			if (string.IsNullOrEmpty(item))
			{
				return;
			}
			bool flag = CropInfo.IsSeedItem(item, crops, delegate(string i)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(i);
				return (itemPrefab != null && CropCatalog.IsFood(itemPrefab)) || KitchenCatalog.All.Any((KitchenInfo k) => k.Inputs.ContainsKey(i));
			});
			if (picks.TryGetValue(item, out Pick value))
			{
				value.Level = Mathf.Min(value.Level, level);
				return;
			}
			picks[item] = new Pick
			{
				Item = item,
				Kind = ((!flag) ? OrderKind.Crop : OrderKind.Seed),
				Level = level
			};
		}

		public static string PickLabel(Pick p)
		{
			if (p.Kind != OrderKind.Herd)
			{
				return Name(p.Item) + ((p.Kind == OrderKind.Seed) ? (" (" + Localization.instance.Localize("$vfh_orders_kind_seed") + ")") : "");
			}
			return Localization.instance.Localize("$vfh_orders_pick_herd", new string[1] { Name(p.Item) });
		}

		public static string Name(string item)
		{
			if (!(item == "*"))
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item);
				ItemDrop val = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if (val == null)
				{
					ZNetScene instance = ZNetScene.instance;
					object obj;
					if (instance == null)
					{
						obj = null;
					}
					else
					{
						GameObject prefab = instance.GetPrefab(item);
						obj = ((prefab != null) ? prefab.GetComponent<Character>() : null);
					}
					Character val2 = (Character)obj;
					if (val2 == null)
					{
						return item;
					}
					return Localization.instance.Localize(val2.m_name);
				}
				return Localization.instance.Localize(val.m_itemData.m_shared.m_name);
			}
			return Localization.instance.Localize("$vfh_orders_everything");
		}

		public static Sprite? Icon(string item)
		{
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(item);
			if (itemPrefab == null)
			{
				return null;
			}
			ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
			if (component == null)
			{
				return null;
			}
			return component.m_itemData.GetIcon();
		}
	}
	internal sealed class OrdersTab : IBoardTab
	{
		private const float RowStep = 26f;

		private const float Top = -150f;

		private const float Bottom = -640f;

		private int _page;

		public string Title => "$vfh_tab_orders";

		public string Signature(HiringBoard board)
		{
			OrderList orderList = BoardOrders.For(board);
			Stock stock = BoardOrders.Stock(board);
			return $"{_page}|{orderList.Serialize()}|" + string.Join(",", orderList.Orders.Select((ProductionOrder o) => OrderPicks.Have(board, stock, o))) + "|" + string.Join(",", OrderPicks.Jobs.Select((JobType j) => Worker(board, j)?.Name ?? "-"));
		}

		private static ContractEntry? Worker(HiringBoard board, JobType job)
		{
			if (board.Zdo != null)
			{
				return BoardRosterOps.Read(board.Zdo).Entries.FirstOrDefault((ContractEntry e) => e.Job == job && e.State != ContractState.Leaving);
			}
			return null;
		}

		public void Build(RectTransform root, HiringBoard board)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_0393: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0385: Unknown result type (might be due to invalid IL or missing references)
			PanelUi.Text((Transform)(object)root, "$vfh_orders_overview_hint", 0f, -125f, 800f, 15, (TextAnchor)4, PanelUi.Dim);
			OrderList list = BoardOrders.For(board);
			Stock stock = BoardOrders.Stock(board);
			List<(JobType, ContractEntry, ProductionOrder)> list2 = new List<(JobType, ContractEntry, ProductionOrder)>();
			JobType[] jobs = OrderPicks.Jobs;
			foreach (JobType jobType in jobs)
			{
				List<ProductionOrder> list3 = OrderPicks.For(list, jobType);
				ContractEntry contractEntry = Worker(board, jobType);
				if (list3.Count == 0 && contractEntry == null)
				{
					continue;
				}
				list2.Add((jobType, contractEntry, null));
				if (list3.Count == 0)
				{
					list2.Add((jobType, contractEntry, new ProductionOrder
					{
						Item = ""
					}));
				}
				foreach (ProductionOrder item in list3)
				{
					list2.Add((jobType, contractEntry, item));
				}
			}
			if (list2.Count == 0)
			{
				PanelUi.Text((Transform)(object)root, "$vfh_orders_empty", 0f, -230f, 760f, 17, (TextAnchor)4, PanelUi.Dim);
				return;
			}
			int num = 18;
			int num2 = (list2.Count + num - 1) / num;
			_page = Mathf.Clamp(_page, 0, num2 - 1);
			float num3 = -170f;
			foreach (var (jobType2, contractEntry2, productionOrder) in list2.Skip(_page * num).Take(num))
			{
				if (productionOrder == null)
				{
					string text = ((contractEntry2 != null) ? Localization.instance.Localize("$vfh_orders_overview_worker", new string[3]
					{
						"$vfh_job_" + jobType2.ToString().ToLowerInvariant(),
						contractEntry2.Name,
						contractEntry2.Level.ToString()
					}) : Localization.instance.Localize("$vfh_orders_overview_none", new string[1] { "$vfh_job_" + jobType2.ToString().ToLowerInvariant() }));
					PanelUi.Text((Transform)(object)root, text, 0f, num3 - 4f, 760f, 17, (TextAnchor)3, null, bold: true);
				}
				else if (productionOrder.Item.Length == 0)
				{
					PanelUi.Text((Transform)(object)root, "$vfh_orders_overview_no_orders", 20f, num3, 720f, 14, (TextAnchor)3, PanelUi.Dim);
				}
				else
				{
					int have = OrderPicks.Have(board, stock, productionOrder);
					Sprite val = OrderPicks.Icon(productionOrder.Item);
					if (val != null)
					{
						PanelUi.Icon((Transform)(object)root, val, -360f, num3, 22f);
					}
					PanelUi.Text((Transform)(object)root, OrderPicks.Name(productionOrder.Item), -200f, num3, 280f, 15, (TextAnchor)3, productionOrder.Paused ? new Color?(PanelUi.Dim) : ((Color?)null));
					PanelUi.Text((Transform)(object)root, OrderPicks.KindLabel(productionOrder.Kind), 100f, num3, 300f, 13, (TextAnchor)3, PanelUi.Dim);
					PanelUi.Text((Transform)(object)root, productionOrder.Paused ? Localization.instance.Localize("$vfh_limits_paused") : OrderPicks.Progress(productionOrder, have), 320f, num3, 120f, 15, (TextAnchor)4, (productionOrder.Paused || productionOrder.IsInfinite) ? PanelUi.Dim : (OrderPicks.Met(productionOrder, have) ? PanelUi.Good : PanelUi.Bad));
				}
				num3 -= 26f;
			}
			Pager(root, _page, num2, delegate(int p)
			{
				_page = p;
			});
		}

		internal static void Pager(RectTransform root, int page, int pages, Action<int> go)
		{
			if (pages > 1)
			{
				PanelUi.Button((Transform)(object)root, "<", -70f, -665f, 46f, 32f, delegate
				{
					go(Mathf.Max(0, page - 1));
				});
				PanelUi.Text((Transform)(object)root, $"{page + 1} / {pages}", 0f, -665f, 80f, 17, (TextAnchor)4);
				PanelUi.Button((Transform)(object)root, ">", 70f, -665f, 46f, 32f, delegate
				{
					go(Mathf.Min(pages - 1, page + 1));
				});
			}
		}
	}
	internal static class PanelUi
	{
		public static readonly Color Good = new Color(0.6f, 1f, 0.6f);

		public static readonly Color Bad = new Color(1f, 0.45f, 0.45f);

		public static readonly Color Dim = new Color(0.75f, 0.75f, 0.75f);

		private static readonly Vector2 TopCenter = new Vector2(0.5f, 1f);

		private const float ClickDebounceSeconds = 0.25f;

		private static float _lastClick = -1f;

		public static event Action? Clicked;

		public static Text Text(Transform parent, string text, float x, float y, float width, int size = 18, TextAnchor align = (TextAnchor)4, Color? color = null, bool bold = false)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			Text component = GUIManager.Instance.CreateText(Localization.instance.Localize(text), parent, TopCenter, TopCenter, new Vector2(x, y), bold ? GUIManager.Instance.AveriaSerifBold : GUIManager.Instance.AveriaSerif, size, (Color)(((??)color) ?? GUIManager.Instance.ValheimBeige), true, Color.black, width, (float)(size + 12), false).GetComponent<Text>();
			component.alignment = align;
			return component;
		}

		public static Button Button(Transform parent, string text, float x, float y, float width, float height, Action onClick)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Expected O, but got Unknown
			GameObject obj = GUIManager.Instance.CreateButton(Localization.instance.Localize(text), parent, TopCenter, TopCenter, new Vector2(x, y), width, height);
			ButtonSfx component = obj.GetComponent<ButtonSfx>();
			if ((Object)(object)component != (Object)null)
			{
				component.m_enterSfxPrefab = null;
				component.m_enterSfxPrefabVibrationOnly = null;
				component.m_selectSfxPrefab = null;
				component.m_selectSfxPrefabVibrationOnly = null;
			}
			Button component2 = obj.GetComponent<Button>();
			((UnityEvent)component2.onClick).AddListener((UnityAction)delegate
			{
				if (!(Time.unscaledTime - _lastClick < 0.25f))
				{
					_lastClick = Time.unscaledTime;
					onClick();
					PanelUi.Clicked?.Invoke();
				}
			});
			return component2;
		}

		public static Image Icon(Transform parent, Sprite? sprite, float x, float y, float size)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("icon", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val.transform.SetParent(parent, false);
			RectTransform val2 = (RectTransform)val.transform;
			Vector2 anchorMin = (val2.anchorMax = TopCenter);
			val2.anchorMin = anchorMin;
			val2.anchoredPosition = new Vector2(x, y);
			val2.sizeDelta = new Vector2(size, size);
			Image component = val.GetComponent<Image>();
			component.sprite = sprite;
			component.preserveAspect = true;
			return component;
		}

		public static RectTransform Fill(Transform parent, string name)
		{
			//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_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)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			RectTransform val2 = (RectTransform)val.transform;
			val2.anchorMin = Vector2.zero;
			val2.anchorMax = Vector2.one;
			Vector2 offsetMin = (val2.offsetMax = Vector2.zero);
			val2.offsetMin = offsetMin;
			return val2;
		}

		public static void Clear(Transform t)
		{
			for (int num = t.childCount - 1; num >= 0; num--)
			{
				Object.DestroyImmediate((Object)(object)((Component)t.GetChild(num)).gameObject);
			}
		}
	}
	internal sealed class RosterTab : IBoardTab
	{
		private const float RadiusStep = 5f;

		private string _selected = "";

		private string _confirmDismiss = "";

		private string _confirmRespec = "";

		public string Title => "$vfh_tab_roster";

		public string Signature(HiringBoard board)
		{
			if (board.Zdo == null)
			{
				return "none";
			}
			int num = board.Zdo.GetByteArray("vfh_roster", (byte[])null)?.Aggregate(17, (int h, byte b) => h * 31 + b) ?? 0;
			Cost cost = ((board.Inventory != null) ? BoardStorage.Totals(board.Inventory) : Cost.Zero);
			long num2 = (long)(ZNet.instance.GetTimeSeconds() / 5.0);
			string text = string.Join(",", from h in Hireling.Loaded
				where (Object)(object)h != (Object)null && h.BoardId == board.Id && h.IsParked
				select h.Hid);
			return $"{num}|{_selected}|{_confirmDismiss}|{_confirmRespec}|{cost}|{num2}|{board.Level}|{text}|{VfhConfig.Enhancements.Value}";
		}

		public void Build(RectTransform root, HiringBoard board)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			Roster roster = BoardRosterOps.Read(board.Zdo);
			if (roster.Count == 0)
			{
				PanelUi.Text((Transform)(object)root, "$vfh_tab_roster_empty", 0f, -220f, 560f, 18, (TextAnchor)4, PanelUi.Dim);
				return;
			}
			if (roster.Entries.All((ContractEntry e) => e.ContractId != _selected))
			{
				_selected = roster.Entries[0].ContractId;
			}
			float num = -150f;
			foreach (ContractEntry item in roster.Entries.Take(12))
			{
				ContractEntry entry = item;
				string text = $"{item.Name} — $vfh_job_{item.Job.ToString().ToLowerInvariant()} {item.Level}";
				int num2 = ((VfhConfig.Enhancements.Value && item.State == ContractState.Active) ? EnhancementRules.Owed(EnhancementPicks.Parse(item.Enhancements), item.Level).Count : 0);
				if (num2 > 0)
				{
					text = text + " (" + Localization.instance.Localize("$vfh_enh_owed", new string[1] { num2.ToString() }) + ")";
				}
				((Graphic)((Component)PanelUi.Button((Transform)(object)root, text, -175f, num, 320f, 28f, delegate
				{
					_selected = entry.ContractId;
					_confirmDismiss = "";
				})).GetComponentInChildren<Text>()).color = ((item.ContractId == _selected) ? Color.yellow : StateColor(item));
				num -= 31f;
			}
			Details(root, board, roster, roster.Entries.First((ContractEntry e) => e.ContractId == _selected));
		}

		private void Details(RectTransform root, HiringBoard board, Roster roster, ContractEntry e)
		{
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0570: Unknown result type (might be due to invalid IL or missing references)
			//IL_050e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0507: Unknown result type (might be due to invalid IL or missing references)
			LevelRules levelRules = new LevelRules(DataStore.Current);
			CostCalculator costCalculator = new CostCalculator(DataStore.Current, VfhConfig.RespawnCostFraction.Value);
			Hireling hireling = Hireling.Loaded.FirstOrDefault((Hireling h) => (Object)(object)h != (Object)null && e.Hid.Length > 0 && h.Hid == e.Hid);
			PanelUi.Text((Transform)(object)root, e.Name, 185f, -150f, 320f, 22, (TextAnchor)4, null, bold: true);
			PanelUi.Text((Transform)(object)root, $"$vfh_job_{e.Job.ToString().ToLowerInvariant()} — $vfh_level {e.Level}", 185f, -180f, 320f, 18, (TextAnchor)4);
			PanelUi.Text((Transform)(object)root, Status(e, hireling), 185f, -208f, 320f, 16, (TextAnchor)4, StateColor(e));
			if ((Object)(object)hireling != (Object)null)
			{
				PanelUi.Text((Transform)(object)root, $"$vfh_health {Mathf.CeilToInt(((Character)hireling.Humanoid).GetHealth())}/{Mathf.CeilToInt(((Character)hireling.Humanoid).GetMaxHealth())}", 185f, -234f, 320f, 16, (TextAnchor)4, PanelUi.Dim);
			}
			PanelUi.Text((Transform)(object)root, Localization.instance.Localize("$vfh_contract_upkeep") + " " + ContractsTab.Price(costCalculator.DailyUpkeep(e.Job, e.Level)), 185f, -260f, 320f, 15, (TextAnchor)4, PanelUi.Dim);
			EnhancementPicks enhancementPicks = EnhancementPicks.Parse(e.Enhancements);
			if (VfhConfig.Enhancements.Value && enhancementPicks.Any)
			{
				PanelUi.Text((Transform)(object)root, Localization.instance.Localize("$vfh_enh_roster", new string[1] { string.Join(", ", from id in enhancementPicks.Ids(e.Job)
					select Localization.instance.Localize(EnhancementText.NameKey(e.Job, id))) }), 185f, -279f, 340f, 12, (TextAnchor)4, PanelUi.Dim);
			}
			if (e.State == ContractState.Pending)
			{
				PanelUi.Button((Transform)(object)root, e.RespawnPending ? "$vfh_roster_cancel_dead" : "$vfh_roster_cancel", 185f, -320f, 240f, 38f, delegate
				{
					BoardContracts.Cancel(board, e.ContractId);
				});
			}
			else
			{
				if (e.State != ContractState.Active)
				{
					return;
				}
				IReadOnlyList<Stance> stances = StanceRules.Allowed(e.Job, EnhancementPicks.Parse(e.Enhancements).Has(e.Job, EnhancementId.Watchman));
				int si = Mathf.Max(0, stances.ToList().IndexOf(e.Stance));
				PanelUi.Button((Transform)(object)root, "$vfh_contract_stance $vfh_stance_" + e.Stance.ToString().ToLowerInvariant(), 185f, -300f, 280f, 34f, delegate
				{
					BoardContracts.Edit(board, e.Hid, e.Radius, stances[(si + 1) % stances.Count]);
				});
				PanelUi.Button((Transform)(object)root, "-", 85f, -342f, 44f, 34f, delegate
				{
					BoardContracts.Edit(board, e.Hid, e.Radius - 5f, e.Stance);
				});
				PanelUi.Text((Transform)(object)root, $"$vfh_contract_radius {e.Radius:0} m", 185f, -342f, 160f, 16, (TextAnchor)4);
				PanelUi.Button((Transform)(object)root, "+", 285f, -342f, 44f, 34f, delegate
				{
					BoardContracts.Edit(board, e.Hid, e.Radius + 5f, e.Stance);
				});
				int num = levelRules.MaxHirelingLevel(board.Level);
				if (e.Level < num)
				{
					Cost c = costCalculator.PromotionCost(e.Job, e.Level, e.Level + 1);
					Cost available = ((board.Inventory != null) ? BoardStorage.Totals(board.Inventory) : Cost.Zero);
					((Selectable)PanelUi.Button((Transform)(object)root, Localization.instance.Localize("$vfh_roster_promote", new string[1] { (e.Level + 1).ToString() }), 185f, -390f, 280f, 34f, delegate
					{
						BoardContracts.Promote(board, e.Hid, e.Level + 1);
					})).interactable = c.CoveredBy(available);
					PanelUi.Text((Transform)(object)root, ContractsTab.Price(c), 185f, -420f, 300f, 15, (TextAnchor)4, c.CoveredBy(available) ? PanelUi.Good : PanelUi.Bad);
				}
				if (_confirmDismiss == e.ContractId)
				{
					PanelUi.Text((Transform)(object)root, Localization.instance.Localize("$vfh_confirm_dismiss_short", new string[1] { e.Name }), 185f, -448f, 330f, 15, (TextAnchor)4, PanelUi.Bad);
					PanelUi.Button((Transform)(object)root, "$vfh_yes", 125f, -480f, 100f, 32f, delegate
					{
						_confirmDismiss = "";
						BoardContracts.Dismiss(board.Id, e.Hid);
					});
					PanelUi.Button((Transform)(object)root, "$vfh_no", 245f, -480f, 100f, 32f, delegate
					{
						_confirmDismiss = "";
					});
					return;
				}
				PanelUi.Button((Transform)(object)root, "$vfh_roster_dismiss", 100f, -465f, 150f, 34f, delegate
				{
					_confirmDismiss = e.ContractId;
				});
				if ((Object)(object)hireling == (Object)null || hireling.Mode == HirelingMode.Working)
				{
					bool parked = (Object)(object)hireling != (Object)null && hireling.IsParked;
					PanelUi.Button((Transform)(object)root, parked ? "$vfh_roster_back_to_work" : "$vfh_roster_call", 270f, -465f, 160f, 34f, delegate
					{
						BoardContracts.Park(e.Hid, !parked);
					});
				}
				float num2 = -505f;
				if (VfhConfig.Enhancements.Value && enhancementPicks.Any)
				{
					Cost c2 = EnhancementRules.RespecCost(costCalculator, e.Job, e.Level, DataStore.Current.EnhancementSettings.RespecCostFraction);
					Cost available2 = ((board.Inventory != null) ? BoardStorage.Totals(board.Inventory) : Cost.Zero);
					bool flag = _confirmRespec == e.ContractId;
					((Selectable)PanelUi.Button((Transform)(object)root, Localization.instance.Localize(flag ? "$vfh_enh_respec_confirm" : "$vfh_enh_respec", new string[1] { ContractsTab.Price(c2) }), 185f, num2, 280f, 34f, delegate
					{
						if (_confirmRespec == e.ContractId)
						{
							_confirmRespec = "";
							BoardContracts.Respec(board.Id, e.Hid);
						}
						else
						{
							_confirmRespec = e.ContractId;
						}
					})).interactable = c2.CoveredBy(available2);
					num2 -= 40f;
				}
				if (e.Post != null)
				{
					PanelUi.Button((Transform)(object)root, "$vfh_orders_clear_post", 185f, num2, 280f, 34f, delegate
					{
						BoardContracts.ClearPost(board, e.Hid);
					});
				}
			}
		}

		private static string WaitText(double seconds)
		{
			if (seconds <= 3600.0)
			{
				return $"{Mathf.CeilToInt((float)seconds)}s";
			}
			double num = (((Object)(object)EnvMan.instance != (Object)null) ? ((double)EnvMan.instance.m_dayLengthSec) : 1800.0);
			return Localization.instance.Localize("$vfh_status_days", new string[1] { (seconds / num).ToString("0.0", CultureInfo.InvariantCulture) });
		}

		private static string Status(ContractEntry e, Hireling? live)
		{
			switch (e.State)
			{
			case ContractState.Pending:
			{
				double num2 = e.ArriveAt - ZNet.instance.GetTimeSeconds();
				string text3 = (e.RespawnPending ? "$vfh_status_returning" : "$vfh_status_arriving");
				if (num2 > 0.0)
				{
					return Localization.instance.Localize(text3) + " (" + WaitText(num2) + ")";
				}
				return Localization.instance.Localize((e.RespawnPending && DeathRules.Pays(VfhConfig.DeathMode.Value)) ? "$vfh_status_awaiting_payment" : text3);
			}
			case ContractState.Leaving:
				return "$vfh_status_leaving";
			default:
			{
				if ((Object)(object)live != (Object)null && live.Mode == HirelingMode.Working && live.IsParked)
				{
					return "$vfh_roster_parked";
				}
				if (e.Post != null)
				{
					object obj;
					if (live == null)
					{
						obj = null;
					}
					else
					{
						Z