Decompiled source of FjordFolk v1.0.0

plugins/FjordFolk.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FjordFolk.Beggar;
using FjordFolk.Fisher;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("FjordFolk")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("FjordFolk")]
[assembly: AssemblyTitle("FjordFolk")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace FjordFolk
{
	internal static class Loc
	{
		private const string Prefix = "fjordfolk_";

		private static readonly string[] Languages = new string[2] { "English", "Russian" };

		public static void Register()
		{
			string[] languages = Languages;
			for (int i = 0; i < languages.Length; i++)
			{
				string text = languages[i];
				string text2 = "FjordFolk.Localization." + text + ".txt";
				using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(text2);
				if (stream == null)
				{
					FjordFolkPlugin.Log.LogError((object)("embedded " + text2 + " not found"));
					continue;
				}
				using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8);
				Dictionary<string, string> dictionary = Parse(streamReader.ReadToEnd());
				LocalizationManager.Instance.GetLocalization().AddTranslation(ref text, dictionary);
			}
		}

		public static string Token(string key)
		{
			return "$fjordfolk_" + key;
		}

		public static string T(string key)
		{
			if (Localization.instance == null)
			{
				return key;
			}
			return Localization.instance.Localize(Token(key));
		}

		public static string T(string key, params object[] args)
		{
			return string.Format(T(key), args);
		}

		private static Dictionary<string, string> Parse(string text)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			string[] array = text.Split('\n');
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim().TrimStart('\ufeff');
				if (text2.Length != 0 && !text2.StartsWith("#"))
				{
					int num = text2.IndexOf('=');
					if (num > 0)
					{
						string text3 = text2.Substring(0, num).Trim();
						string value = text2.Substring(num + 1).Trim().Replace("\\n", "\n");
						dictionary["fjordfolk_" + text3] = value;
					}
				}
			}
			return dictionary;
		}
	}
	public class NpcActor : MonoBehaviour, Hoverable, Interactable
	{
		public int m_presetId;

		[NonSerialized]
		public bool m_portrait;

		private static readonly int s_appearanceVersion = StringExtensionMethods.GetStableHashCode("fjordfolk_appearance_v1");

		private ZNetView m_nview;

		private VisEquipment m_vis;

		private FisherWorkplace m_work;

		private BeggarBehaviour m_beggar;

		private NpcPreset m_preset;

		private NpcEmotes m_emotes;

		private void Awake()
		{
			FjordFolkPlugin.Guard("NpcActor.Awake", delegate
			{
				m_nview = ((Component)this).GetComponent<ZNetView>();
				m_vis = ((Component)this).GetComponent<VisEquipment>();
				m_work = ((Component)this).GetComponent<FisherWorkplace>();
				m_beggar = ((Component)this).GetComponent<BeggarBehaviour>();
				m_preset = NpcPresets.Get(m_presetId);
				if ((Object)(object)m_vis == (Object)null || m_preset == null)
				{
					FjordFolkPlugin.Log.LogWarning((object)$"{((Object)this).name}: missing VisEquipment or preset {m_presetId}");
				}
				else
				{
					ZDO val = (((Object)(object)m_nview != (Object)null) ? m_nview.GetZDO() : null);
					if (val == null)
					{
						DressGhost(m_preset);
					}
					else if (m_nview.IsOwner() && !val.GetBool(s_appearanceVersion, false))
					{
						WriteAppearance(val, m_preset);
						val.Set(s_appearanceVersion, true);
					}
				}
			});
		}

		private void Start()
		{
			FjordFolkPlugin.Guard("NpcActor.Start", delegate
			{
				Animator componentInChildren = ((Component)this).GetComponentInChildren<Animator>();
				if (!((Object)(object)componentInChildren == (Object)null) && m_preset != null)
				{
					m_emotes = new NpcEmotes(componentInChildren);
					m_emotes.SkipWakeup();
					if (!m_portrait)
					{
						ApplyPose();
					}
				}
			});
		}

		private void WriteAppearance(ZDO zdo, NpcPreset p)
		{
			//IL_0019: 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)
			zdo.Set(ZDOVars.s_modelIndex, p.Model, false);
			zdo.Set(ZDOVars.s_skinColor, p.SkinColor);
			zdo.Set(ZDOVars.s_hairColor, p.HairColor);
			zdo.Set(ZDOVars.s_hairItem, ItemHash(HairName(p)), false);
			zdo.Set(ZDOVars.s_beardItem, ItemHash(BeardName(p)), false);
			zdo.Set(ZDOVars.s_chestItem, ItemHash(p.Chest), false);
			zdo.Set(ZDOVars.s_legItem, ItemHash(p.Legs), false);
			zdo.Set(ZDOVars.s_helmetItem, ItemHash(p.Helmet), false);
			zdo.Set(ZDOVars.s_shoulderItem, ItemHash(p.Shoulder), false);
			zdo.Set(ZDOVars.s_rightItem, ItemHash(p.RightItem), false);
			zdo.Set(ZDOVars.s_leftItem, ItemHash(p.LeftItem), false);
		}

		private void DressGhost(NpcPreset p)
		{
			//IL_0018: 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_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			m_vis.m_modelIndex = p.Model;
			m_vis.m_skinColor = p.SkinColor;
			m_vis.m_hairColor = p.HairColor;
			m_vis.m_hairItem = ItemHash(HairName(p));
			m_vis.m_beardItem = ItemHash(BeardName(p));
			m_vis.m_chestItem = ItemHash(p.Chest);
			m_vis.m_legItem = ItemHash(p.Legs);
			m_vis.m_helmetItem = ItemHash(p.Helmet);
			m_vis.m_shoulderItem = ItemHash(p.Shoulder);
			m_vis.m_rightItem = ItemHash(p.RightItem);
			m_vis.m_leftItem = ItemHash(p.LeftItem);
		}

		private static string HairName(NpcPreset p)
		{
			return Customization("Hair", p.HairIndex);
		}

		private static string BeardName(NpcPreset p)
		{
			return Customization("Beard", p.BeardIndex);
		}

		private static string Customization(string prefix, int index)
		{
			if (index <= 0 || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return "";
			}
			List<string> list = (from i in ObjectDB.instance.GetAllItems((ItemType)10, prefix)
				where (Object)(object)i != (Object)null && !((Object)i).name.EndsWith("None")
				select ((Object)i).name into n
				orderby n.Length, n
				select n).ToList();
			if (list.Count != 0)
			{
				return list[Mathf.Clamp(index, 1, list.Count) - 1];
			}
			return "";
		}

		private int ItemHash(string itemName)
		{
			if (string.IsNullOrEmpty(itemName))
			{
				return 0;
			}
			if ((Object)(object)ObjectDB.instance != (Object)null && (Object)(object)ObjectDB.instance.GetItemPrefab(itemName) == (Object)null)
			{
				FjordFolkPlugin.Log.LogWarning((object)(((Object)this).name + ": item '" + itemName + "' does not exist, slot left empty"));
				return 0;
			}
			return StringExtensionMethods.GetStableHashCode(itemName);
		}

		private void ApplyPose()
		{
			if (m_emotes != null && m_preset != null)
			{
				((MonoBehaviour)this).CancelInvoke("ApplyPose");
				if (string.IsNullOrEmpty(m_preset.Pose))
				{
					m_emotes.StopAll();
				}
				else if (m_emotes.Play(m_preset.Pose) == "missing")
				{
					FjordFolkPlugin.Log.LogWarning((object)(((Object)this).name + ": pose '" + m_preset.Pose + "' not in animator"));
				}
			}
		}

		public void PlayGestureLocal(string emote, float returnAfter = 3.5f)
		{
			if (m_emotes != null && !string.IsNullOrEmpty(emote))
			{
				((MonoBehaviour)this).CancelInvoke("ApplyPose");
				m_emotes.Play(emote);
				if (returnAfter > 0f)
				{
					((MonoBehaviour)this).Invoke("ApplyPose", returnAfter);
				}
			}
		}

		public void ReturnToPose()
		{
			ApplyPose();
		}

		public string GetHoverName()
		{
			if (m_preset == null)
			{
				return "";
			}
			return m_preset.Name;
		}

		public string GetHoverText()
		{
			if (m_preset == null)
			{
				return "";
			}
			if ((Object)(object)m_work != (Object)null && m_work.IsLive)
			{
				return m_work.HoverText(m_preset.Name);
			}
			if ((Object)(object)m_beggar != (Object)null && m_beggar.IsLive)
			{
				return m_beggar.HoverText(m_preset.Name);
			}
			return m_preset.Name;
		}

		public float GetHoverOffset()
		{
			return 0f;
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (hold || m_preset == null)
			{
				return false;
			}
			FjordFolkPlugin.Guard("NpcActor.Interact", delegate
			{
				if ((Object)(object)m_work != (Object)null)
				{
					if (m_work.IsLive && !FisherPanel.JustClosed)
					{
						FisherPanel.Open(m_work);
					}
				}
				else if ((Object)(object)m_beggar != (Object)null)
				{
					m_beggar.GiveCoin(user);
				}
			});
			return true;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			if ((Object)(object)m_beggar == (Object)null || !m_beggar.IsLive || !BeggarBehaviour.IsCoin(item))
			{
				return false;
			}
			FjordFolkPlugin.Guard("NpcActor.UseItem", delegate
			{
				m_beggar.GiveCoin(user);
			});
			return true;
		}

		public void Say(string text)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			Chat.instance.SetNpcText(((Component)this).gameObject, Vector3.up * 2.1f, 25f, 6f, "", text, false);
		}
	}
	internal sealed class NpcDialogue
	{
		private const string EmbeddedPrefix = "FjordFolk.Dialogue.";

		private static readonly string[] FallbackLanguages = new string[2] { "English", "Russian" };

		private static readonly Dictionary<string, NpcDialogue> s_cache = new Dictionary<string, NpcDialogue>();

		private static readonly Random s_random = new Random();

		private readonly Dictionary<string, List<string>> m_sections;

		private readonly Dictionary<string, Queue<string>> m_bags = new Dictionary<string, Queue<string>>();

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

		public string Source { get; }

		private NpcDialogue(Dictionary<string, List<string>> sections, string source)
		{
			m_sections = sections;
			Source = source;
		}

		public static NpcDialogue For(string dialogueId)
		{
			string text = ((Localization.instance != null) ? Localization.instance.GetSelectedLanguage() : "English");
			string key = dialogueId + "|" + text;
			if (s_cache.TryGetValue(key, out var value))
			{
				return value;
			}
			NpcDialogue npcDialogue = Load(dialogueId, text);
			s_cache[key] = npcDialogue;
			FjordFolkPlugin.Log.LogDebug((object)("dialogue '" + dialogueId + "' for " + text + ": " + npcDialogue.Source + ", " + $"{npcDialogue.m_sections.Count} sections, {Total(npcDialogue.m_sections)} lines"));
			return npcDialogue;
		}

		public bool Has(string section)
		{
			if (m_sections.TryGetValue(section, out var value))
			{
				return value.Count > 0;
			}
			return false;
		}

		public string Pick(string section)
		{
			if (!Has(section))
			{
				return null;
			}
			if (!m_bags.TryGetValue(section, out var value) || value.Count == 0)
			{
				value = Refill(section);
				m_bags[section] = value;
			}
			string text = value.Dequeue();
			m_lastPicked[section] = text;
			return text;
		}

		private Queue<string> Refill(string section)
		{
			List<string> list = new List<string>(m_sections[section]);
			for (int num = list.Count - 1; num > 0; num--)
			{
				int num2 = s_random.Next(num + 1);
				List<string> list2 = list;
				int index = num;
				List<string> list3 = list;
				int index2 = num2;
				string value = list[num2];
				string value2 = list[num];
				list2[index] = value;
				list3[index2] = value2;
			}
			if (list.Count > 1 && m_lastPicked.TryGetValue(section, out var value3) && list[0] == value3)
			{
				List<string> list3 = list;
				List<string> list2 = list;
				int index2 = list.Count - 1;
				string value2 = list[list.Count - 1];
				string value = list[0];
				list3[0] = value2;
				list2[index2] = value;
			}
			return new Queue<string>(list);
		}

		private static NpcDialogue Load(string dialogueId, string language)
		{
			List<string> list = new List<string> { language };
			string[] fallbackLanguages = FallbackLanguages;
			foreach (string item in fallbackLanguages)
			{
				if (!list.Contains(item))
				{
					list.Add(item);
				}
			}
			foreach (string item2 in list)
			{
				string text = dialogueId + "." + item2 + ".txt";
				string text2 = Path.Combine(Paths.ConfigPath, "FjordFolk", "dialogue", text);
				if (File.Exists(text2))
				{
					return new NpcDialogue(Parse(File.ReadAllText(text2, Encoding.UTF8)), "override " + text2);
				}
				using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("FjordFolk.Dialogue." + text);
				if (stream == null)
				{
					continue;
				}
				using StreamReader streamReader = new StreamReader(stream, Encoding.UTF8);
				string source = ((item2 == language) ? ("embedded " + text) : ("embedded " + text + " (no " + language + " translation)"));
				return new NpcDialogue(Parse(streamReader.ReadToEnd()), source);
			}
			FjordFolkPlugin.Log.LogWarning((object)("no dialogue file for '" + dialogueId + "' in any language"));
			return new NpcDialogue(new Dictionary<string, List<string>>(), "none");
		}

		private static Dictionary<string, List<string>> Parse(string text)
		{
			Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
			List<string> value = null;
			string[] array = text.Split('\n');
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim().TrimStart('\ufeff');
				if (text2.Length == 0 || text2.StartsWith("#"))
				{
					continue;
				}
				if (text2.StartsWith("[") && text2.EndsWith("]"))
				{
					string key = text2.Substring(1, text2.Length - 2).Trim();
					if (!dictionary.TryGetValue(key, out value))
					{
						value = (dictionary[key] = new List<string>());
					}
				}
				else
				{
					value?.Add(text2);
				}
			}
			return dictionary;
		}

		private static int Total(Dictionary<string, List<string>> sections)
		{
			int num = 0;
			foreach (List<string> value in sections.Values)
			{
				num += value.Count;
			}
			return num;
		}
	}
	internal sealed class NpcEmotes
	{
		private static bool s_parametersLogged;

		private readonly Animator m_animator;

		private readonly Dictionary<string, AnimatorControllerParameter> m_params = new Dictionary<string, AnimatorControllerParameter>();

		private string m_activeLoop;

		public NpcEmotes(Animator animator)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			m_animator = animator;
			AnimatorControllerParameter[] parameters = animator.parameters;
			foreach (AnimatorControllerParameter val in parameters)
			{
				m_params[val.name.ToLowerInvariant()] = val;
			}
			if (!s_parametersLogged)
			{
				s_parametersLogged = true;
				List<string> list = new List<string>();
				parameters = animator.parameters;
				foreach (AnimatorControllerParameter val2 in parameters)
				{
					list.Add($"{val2.name}:{val2.type}");
				}
				FjordFolkPlugin.Log.LogDebug((object)string.Format("animator parameters ({0}): {1}", list.Count, string.Join(", ", list)));
			}
		}

		public void SkipWakeup()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			if (m_params.TryGetValue("wakeup", out var value) && (int)value.type == 4)
			{
				m_animator.SetBool(value.name, false);
			}
		}

		public string Play(string emote)
		{
			//IL_0051: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Invalid comparison between Unknown and I4
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Invalid comparison between Unknown and I4
			if (!m_params.TryGetValue("emote_" + emote.ToLowerInvariant(), out var value))
			{
				return "missing";
			}
			StopLoop();
			if (m_params.TryGetValue("emote_stop", out var value2))
			{
				m_animator.ResetTrigger(value2.name);
			}
			AnimatorControllerParameterType type = value.type;
			if ((int)type != 4)
			{
				if ((int)type == 9)
				{
					m_animator.SetTrigger(value.name);
					return "once";
				}
				return "missing";
			}
			m_animator.SetBool(value.name, true);
			m_activeLoop = value.name;
			return "loop";
		}

		public void StopAll()
		{
			StopLoop();
			if (m_params.TryGetValue("emote_stop", out var value))
			{
				m_animator.SetTrigger(value.name);
			}
		}

		private void StopLoop()
		{
			if (!string.IsNullOrEmpty(m_activeLoop))
			{
				m_animator.SetBool(m_activeLoop, false);
				m_activeLoop = null;
				if (m_params.TryGetValue("emote_stop", out var value))
				{
					m_animator.SetTrigger(value.name);
				}
			}
		}
	}
	public class NpcGreeter : MonoBehaviour
	{
		public string m_dialogueId = "";

		public float m_greetRange = 5f;

		public float m_byeRange = 9f;

		public string m_gesture = "wave";

		public bool m_holdGesture;

		private const float CheckInterval = 0.25f;

		private const float QuickReturnWindow = 120f;

		private const float PestWindow = 150f;

		private const int PestVisits = 2;

		private const float ShortVisit = 6f;

		private ZNetView m_nview;

		private NpcActor m_actor;

		private bool m_near;

		private float m_nearSince;

		private float m_leftAt = -9999f;

		private readonly List<float> m_visits = new List<float>();

		private float m_nextCheck;

		private string m_pending;

		private float m_pendingAt;

		private void Awake()
		{
			m_nview = ((Component)this).GetComponent<ZNetView>();
			m_actor = ((Component)this).GetComponent<NpcActor>();
		}

		private void Update()
		{
			if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid() || string.IsNullOrEmpty(m_dialogueId))
			{
				return;
			}
			if (m_pending != null && Time.time >= m_pendingAt)
			{
				string action = m_pending;
				m_pending = null;
				FjordFolkPlugin.Guard("NpcGreeter." + action, delegate
				{
					Perform(action);
				});
			}
			if (!(Time.time < m_nextCheck))
			{
				m_nextCheck = Time.time + 0.25f;
				FjordFolkPlugin.Guard("NpcGreeter.Update", CheckPlayer);
			}
		}

		private void CheckPlayer()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead())
			{
				return;
			}
			float num = Vector3.Distance(((Component)localPlayer).transform.position, ((Component)this).transform.position);
			if (!m_near && num < m_greetRange)
			{
				m_near = true;
				m_nearSince = Time.time;
				Schedule("greet", Random.Range(0.35f, 1.1f));
			}
			else if (m_near && num > m_byeRange)
			{
				m_near = false;
				if (m_pending == "greet")
				{
					m_pending = null;
					return;
				}
				m_leftAt = Time.time;
				Schedule("bye", Random.Range(0.2f, 0.7f));
			}
		}

		private void Schedule(string action, float delay)
		{
			m_pending = action;
			m_pendingAt = Time.time + delay;
		}

		private void Perform(string action)
		{
			NpcDialogue dialogue = NpcDialogue.For(m_dialogueId);
			if (action == "greet")
			{
				Greet(dialogue);
			}
			else
			{
				Goodbye(dialogue);
			}
		}

		private void Greet(NpcDialogue dialogue)
		{
			m_visits.RemoveAll((float t) => Time.time - t > 150f);
			int count = m_visits.Count;
			m_visits.Add(Time.time);
			string text = ((count >= 2) ? "greet_pest" : ((!(Time.time - m_leftAt < 120f)) ? (Lore(dialogue) ?? Situational("greet", "greet_first", dialogue)) : "greet_again"));
			bool flag = text == "greet_pest";
			bool num = flag || m_holdGesture || Random.value < 0.85f;
			bool flag2 = !string.IsNullOrEmpty(m_gesture) && (m_holdGesture || (!flag && Random.value < 0.8f));
			if (flag2)
			{
				m_actor?.PlayGestureLocal(m_gesture, m_holdGesture ? 0f : 3.5f);
			}
			string text2 = (num ? (dialogue.Pick(text) ?? dialogue.Pick("greet_first")) : null);
			if (text2 != null)
			{
				m_actor?.Say(text2);
			}
			Report("greet", text, flag2, text2);
		}

		private void Goodbye(NpcDialogue dialogue)
		{
			if (m_holdGesture)
			{
				m_actor?.ReturnToPose();
			}
			string section = ((Time.time - m_nearSince < 6f && Random.value < 0.7f) ? "bye_short" : Situational("bye", "bye", dialogue));
			string text = ((Random.value < 0.7f) ? (dialogue.Pick(section) ?? dialogue.Pick("bye")) : null);
			if (text != null)
			{
				m_actor?.Say(text);
			}
			Report("bye", section, gestured: false, text);
		}

		private static string Lore(NpcDialogue dialogue)
		{
			if (dialogue.Has("greet_brother") && BeggarLore.MetRecently && Random.value < 0.5f)
			{
				return "greet_brother";
			}
			if (dialogue.Has("greet_hired") && Random.value < 0.35f && FisherRules.FishermanExists())
			{
				return "greet_hired";
			}
			return null;
		}

		private static string Situational(string prefix, string plain, NpcDialogue dialogue)
		{
			EnvMan instance = EnvMan.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return plain;
			}
			float dayFraction = instance.GetDayFraction();
			return Try("rain", EnvMan.IsWet(), 0.45f) ?? Try("night", EnvMan.IsNight(), 0.4f) ?? Try("morning", dayFraction > 0.22f && dayFraction < 0.38f, 0.35f) ?? Try("evening", dayFraction > 0.62f && dayFraction < 0.76f, 0.35f) ?? plain;
			string Try(string suffix, bool when, float chance)
			{
				string text = prefix + "_" + suffix;
				if (!when || !dialogue.Has(text) || !(Random.value < chance))
				{
					return null;
				}
				return text;
			}
		}

		private void Report(string action, string section, bool gestured, string line)
		{
			string text = ((line == null) ? "(silent)" : ("\"" + line + "\""));
			FjordFolkPlugin.Log.LogDebug((object)(m_dialogueId + " " + action + ": [" + section + "]" + (gestured ? (" +" + m_gesture) : "") + " " + text));
		}
	}
	internal sealed class NpcIcons : MonoBehaviour
	{
		private static readonly List<string> s_prefabs = new List<string>();

		private static bool s_started;

		public static void Add(string prefabName)
		{
			if (!s_prefabs.Contains(prefabName))
			{
				s_prefabs.Add(prefabName);
			}
		}

		private void Update()
		{
			if (!s_started && !((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)ZNetScene.instance == (Object)null) && !((Object)(object)ObjectDB.instance == (Object)null))
			{
				s_started = true;
				((MonoBehaviour)this).StartCoroutine(RenderAll());
			}
		}

		private IEnumerator RenderAll()
		{
			yield return (object)new WaitForSeconds(3f);
			int rendered = 0;
			foreach (string name in s_prefabs)
			{
				GameObject prefab = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(name) : null);
				Piece piece = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Piece>() : null);
				if ((Object)(object)piece == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
				{
					continue;
				}
				GameObject stage = null;
				FjordFolkPlugin.Guard("NpcIcons.Stage", delegate
				{
					stage = Stage(prefab);
				});
				if ((Object)(object)stage == (Object)null)
				{
					continue;
				}
				yield return (object)new WaitForSeconds(1.5f);
				FjordFolkPlugin.Guard("NpcIcons.Render", delegate
				{
					//IL_0026: Unknown result type (might be due to invalid IL or missing references)
					//IL_002b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0032: Unknown result type (might be due to invalid IL or missing references)
					//IL_0039: 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_0053: Unknown result type (might be due to invalid IL or missing references)
					//IL_005f: Expected O, but got Unknown
					//IL_006a: Unknown result type (might be due to invalid IL or missing references)
					//IL_006f: Unknown result type (might be due to invalid IL or missing references)
					bool value = DebugConfig.ExportIcons.Value;
					int num = (value ? 512 : 128);
					Sprite val = RenderManager.Instance.Render(new RenderRequest(stage)
					{
						Width = num,
						Height = num,
						Rotation = Quaternion.Euler(8f, -30f, 0f),
						UseCache = false
					});
					if (!((Object)(object)val == (Object)null))
					{
						Rect rect = val.rect;
						if (!(((Rect)(ref rect)).width <= 1f))
						{
							piece.m_icon = val;
							int num2 = rendered;
							rendered = num2 + 1;
							if (value)
							{
								string text = Path.Combine(Paths.ConfigPath, "FjordFolk");
								Directory.CreateDirectory(text);
								string text2 = Path.Combine(text, "icon_" + name + ".png");
								File.WriteAllBytes(text2, ImageConversion.EncodeToPNG(val.texture));
								FjordFolkPlugin.Log.LogInfo((object)("icon saved to " + text2));
							}
						}
					}
				});
				Object.Destroy((Object)(object)stage);
			}
			FjordFolkPlugin.Log.LogDebug((object)$"NPC icons rendered: {rendered} of {s_prefabs.Count}");
		}

		private static GameObject Stage(GameObject prefab)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			Vector3 val = ((Component)Player.m_localPlayer).transform.position + new Vector3(0f, 600f, 0f);
			ZNetView.m_forceDisableInit = true;
			GameObject val2;
			try
			{
				val2 = Object.Instantiate<GameObject>(prefab, val, Quaternion.identity);
			}
			finally
			{
				ZNetView.m_forceDisableInit = false;
			}
			NpcActor component = val2.GetComponent<NpcActor>();
			if ((Object)(object)component != (Object)null)
			{
				component.m_portrait = true;
			}
			Collider[] componentsInChildren = val2.GetComponentsInChildren<Collider>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].enabled = false;
			}
			Animator[] componentsInChildren2 = val2.GetComponentsInChildren<Animator>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				componentsInChildren2[i].cullingMode = (AnimatorCullingMode)0;
			}
			return val2;
		}
	}
	internal static class NpcPieces
	{
		private static readonly HashSet<string> KeepTypes = new HashSet<string>
		{
			"Transform", "ZNetView", "VisEquipment", "Animator", "SkinnedMeshRenderer", "MeshRenderer", "MeshFilter", "LODGroup", "CapsuleCollider", "SphereCollider",
			"BoxCollider", "MeshCollider", "MagicaCloth", "MagicaCapsuleCollider", "MagicaSphereCollider", "MagicaPlaneCollider"
		};

		public static void RegisterAll()
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab("Player");
			if ((Object)(object)prefab == (Object)null)
			{
				FjordFolkPlugin.Log.LogError((object)"vanilla 'Player' prefab not found, nothing registered");
				return;
			}
			FisherPieces.Register(prefab);
			BeggarPieces.Register(prefab);
		}

		internal static GameObject BuildNpc(GameObject player, string prefabName, int presetId)
		{
			GameObject val = PrefabManager.Instance.CreateClonedPrefab(prefabName, player);
			Strip(val);
			ZNetView component = val.GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null)
			{
				FjordFolkPlugin.Log.LogError((object)(prefabName + ": ZNetView lost during strip"));
				return null;
			}
			component.m_persistent = true;
			val.AddComponent<NpcActor>().m_presetId = presetId;
			NpcPreset npcPreset = NpcPresets.Get(presetId);
			if (npcPreset != null && !string.IsNullOrEmpty(npcPreset.DialogueId))
			{
				NpcGreeter npcGreeter = val.AddComponent<NpcGreeter>();
				npcGreeter.m_dialogueId = npcPreset.DialogueId;
				npcGreeter.m_gesture = npcPreset.Greet;
				npcGreeter.m_holdGesture = npcPreset.HoldGreet;
			}
			if ((Object)(object)val.GetComponent<Piece>() == (Object)null)
			{
				val.AddComponent<Piece>();
			}
			return val;
		}

		internal static void AddToHammer(GameObject prefab, string nameToken, string descriptionToken, string iconItem, RequirementConfig[] requirements)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0028: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			if (!((Object)(object)prefab == (Object)null))
			{
				PieceConfig val = new PieceConfig
				{
					Name = nameToken,
					Description = descriptionToken,
					PieceTable = "Hammer",
					Category = "Misc",
					Icon = IconOf(iconItem),
					Requirements = requirements
				};
				PieceManager.Instance.AddPiece(new CustomPiece(prefab, false, val));
				NpcIcons.Add(((Object)prefab).name);
				FjordFolkPlugin.Log.LogDebug((object)("registered " + ((Object)prefab).name));
			}
		}

		private static void Strip(GameObject prefab)
		{
			for (int i = 0; i < 10; i++)
			{
				List<Component> list = (from c in prefab.GetComponentsInChildren<Component>(true)
					where (Object)(object)c != (Object)null && !KeepTypes.Contains(((object)c).GetType().Name)
					orderby (!(c is MonoBehaviour)) ? 1 : 0
					select c).ToList();
				if (list.Count == 0)
				{
					break;
				}
				foreach (Component item in list)
				{
					Object.DestroyImmediate((Object)(object)item);
				}
				int num = prefab.GetComponentsInChildren<Component>(true).Count((Component c) => (Object)(object)c != (Object)null && !KeepTypes.Contains(((object)c).GetType().Name));
				if (num == list.Count)
				{
					FjordFolkPlugin.Log.LogWarning((object)$"{((Object)prefab).name}: {num} components could not be removed");
					break;
				}
			}
			int num2 = LayerMask.NameToLayer("piece");
			Collider[] componentsInChildren = prefab.GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if (val.isTrigger)
				{
					Object.DestroyImmediate((Object)(object)val);
				}
				else if (num2 >= 0)
				{
					((Component)val).gameObject.layer = num2;
				}
			}
		}

		internal static Sprite IconOf(string itemName)
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab(itemName);
			Sprite[] array = ((!((Object)(object)prefab != (Object)null)) ? null : prefab.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_icons);
			if (array == null || array.Length == 0)
			{
				return null;
			}
			return array[0];
		}
	}
	internal sealed class NpcPreset
	{
		public int Id;

		public string NameKey;

		public int Model;

		public Vector3 SkinColor;

		public Vector3 HairColor;

		public int HairIndex;

		public int BeardIndex;

		public string Chest = "";

		public string Legs = "";

		public string Helmet = "";

		public string Shoulder = "";

		public string RightItem = "";

		public string LeftItem = "";

		public string Pose = "";

		public string Greet = "";

		public bool HoldGreet;

		public string DialogueId = "";

		public string Name => Loc.T(NameKey);
	}
	internal static class NpcPresets
	{
		public const int FishermanId = 1;

		public const int BeggarId = 2;

		private static readonly NpcPreset[] All = new NpcPreset[2]
		{
			new NpcPreset
			{
				Id = 1,
				NameKey = "knut_name",
				Model = 0,
				SkinColor = new Vector3(0.85f, 0.72f, 0.6f),
				HairColor = new Vector3(0.62f, 0.28f, 0.12f),
				HairIndex = 9,
				BeardIndex = 2,
				Chest = "ArmorRagsChest",
				Legs = "ArmorRagsLegs",
				Helmet = "HelmetFishingHat",
				RightItem = "FishingRod",
				Pose = "sit",
				Greet = "wave",
				DialogueId = "fisher"
			},
			new NpcPreset
			{
				Id = 2,
				NameKey = "ulv_name",
				Model = 0,
				SkinColor = new Vector3(0.85f, 0.72f, 0.6f),
				HairColor = new Vector3(0.45f, 0.34f, 0.22f),
				HairIndex = 8,
				BeardIndex = 10,
				Chest = "ArmorRagsChest",
				Legs = "ArmorRagsLegs",
				Helmet = "HelmetSweatBand",
				Pose = "sit",
				Greet = "cower",
				HoldGreet = true,
				DialogueId = "beggar"
			}
		};

		public static NpcPreset Get(int id)
		{
			NpcPreset[] all = All;
			foreach (NpcPreset npcPreset in all)
			{
				if (npcPreset.Id == id)
				{
					return npcPreset;
				}
			}
			return null;
		}
	}
	[BepInPlugin("fedorovdgap.fjordfolk", "Fjord Folk", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInProcess("valheim.exe")]
	public class FjordFolkPlugin : BaseUnityPlugin
	{
		public const string PluginId = "fedorovdgap.fjordfolk";

		public const string PluginName = "Fjord Folk";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		private static readonly HashSet<string> s_failedOnce = new HashSet<string>();

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			FisherConfig.Bind(((BaseUnityPlugin)this).Config);
			BeggarConfig.Bind(((BaseUnityPlugin)this).Config);
			DebugConfig.Bind(((BaseUnityPlugin)this).Config);
			Guard("Loc.Register", Loc.Register);
			Guard("Harmony", delegate
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				new Harmony("fedorovdgap.fjordfolk").PatchAll(typeof(FjordFolkPlugin).Assembly);
			});
			((Component)this).gameObject.AddComponent<BeggarSpawner>();
			((Component)this).gameObject.AddComponent<NpcIcons>();
			PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable;
		}

		private void OnVanillaPrefabsAvailable()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable;
			Guard("RegisterAll", NpcPieces.RegisterAll);
		}

		internal static void Guard(string where, Action action)
		{
			try
			{
				action();
			}
			catch (Exception arg)
			{
				if (s_failedOnce.Add(where))
				{
					Log.LogError((object)$"{where} failed (repeats are not logged): {arg}");
				}
			}
		}
	}
	internal static class DebugConfig
	{
		public static ConfigEntry<bool> TestChest;

		public static ConfigEntry<bool> WriteUiLayout;

		public static ConfigEntry<bool> ExportIcons;

		public static void Bind(ConfigFile config)
		{
			TestChest = config.Bind<bool>("Debug", "TestChest", false, "Adds a chest for one wood to the hammer that fills itself with everything needed to test the fisherman. Restart the game after changing.");
			WriteUiLayout = config.Bind<bool>("Debug", "WriteUiLayout", false, "Writes the layout of the fisherman's window to the config folder when it first opens.");
			ExportIcons = config.Bind<bool>("Debug", "ExportIcons", false, "Saves the rendered hammer icons as PNG files to the config folder.");
		}
	}
	internal static class VanillaUi
	{
		public sealed class Window
		{
			public RectTransform Root;

			public float Width;

			public TMP_Text Title;

			public Image Icon;

			public TMP_Text LevelText;

			public UITooltip LevelTooltip;

			public readonly List<Button> Tabs = new List<Button>();

			public Rect ContentArea;

			public GameObject List;

			public RectTransform ListRoot;

			public float ListSpacing;

			public GameObject Details;

			public Image DetailsIcon;

			public TMP_Text DetailsName;

			public TMP_Text DetailsText;

			public TMP_Text DetailsFooter;

			public readonly List<Tile> Requirements = new List<Tile>();

			public TMP_Text RequirementLevel;

			public UITooltip RequirementLevelTooltip;

			public Button ActionButton;
		}

		public sealed class ListEntry
		{
			public GameObject Root;

			public Image Icon;

			public TMP_Text Name;

			public TMP_Text Badge;

			public GameObject Selected;

			public Button Button;
		}

		public enum TextStyle
		{
			Header,
			Body,
			Big
		}

		public sealed class Slot
		{
			public RectTransform Rect;

			public Image Icon;

			public TMP_Text Amount;

			public GameObject Selected;

			public Button Button;

			public UITooltip Tooltip;

			public void Show(Sprite icon, int amount, bool dim)
			{
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)Icon != (Object)null)
				{
					Icon.sprite = icon;
					((Behaviour)Icon).enabled = (Object)(object)icon != (Object)null;
					((Graphic)Icon).color = (Color)(dim ? new Color(1f, 1f, 1f, 0.45f) : Color.white);
				}
				if ((Object)(object)Amount != (Object)null)
				{
					Amount.text = ((amount > 0) ? amount.ToString() : "");
					((Component)Amount).gameObject.SetActive(amount > 0);
				}
			}
		}

		public sealed class Tile
		{
			public GameObject Root;

			public Image Icon;

			public TMP_Text Name;

			public TMP_Text Amount;

			public UITooltip Tooltip;
		}

		private static readonly HashSet<string> Behaviours = new HashSet<string> { "SkillsDialog", "UIGroupHandler", "UIGamePad", "Localize", "UIInputHandler", "UIDragHandler", "InventoryElement", "ScrollRectEnsureVisible", "EventTrigger" };

		private static readonly HashSet<string> Layouts = new HashSet<string> { "ContentSizeFitter", "LayoutElement", "VerticalLayoutGroup", "HorizontalLayoutGroup", "GridLayoutGroup" };

		public static readonly Color Red = new Color(1f, 0.25f, 0.25f);

		private static GameObject s_holder;

		private static bool s_dumped;

		public static Vector2 ButtonSize => SizeOf((RectTransform)((Component)InventoryGui.instance.m_takeAllButton).transform, new Vector2(133f, 40f));

		public static float SlotNaturalSize => SizeOf((RectTransform)InventoryGui.instance.m_playerGrid.m_elementPrefab.transform, new Vector2(64f, 64f)).x;

		public static float SlotSpacing => Mathf.Max(SlotNaturalSize, InventoryGui.instance.m_playerGrid.m_elementSpace);

		public static string MissingPart()
		{
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return "InventoryGui";
			}
			if ((Object)(object)instance.m_crafting == (Object)null || (Object)(object)instance.m_craftingStationName == (Object)null)
			{
				return "crafting panel";
			}
			if ((Object)(object)instance.m_tabCraft == (Object)null || (Object)(object)instance.m_tabUpgrade == (Object)null)
			{
				return "tabs";
			}
			if ((Object)(object)instance.m_recipeListRoot == (Object)null || (Object)(object)instance.m_recipeElementPrefab == (Object)null)
			{
				return "recipe list";
			}
			if ((Object)(object)instance.m_recipeName == (Object)null || (Object)(object)instance.m_recipeDecription == (Object)null || (Object)(object)instance.m_itemCraftType == (Object)null)
			{
				return "description";
			}
			if (instance.m_recipeRequirementList == null || instance.m_recipeRequirementList.Length == 0)
			{
				return "requirements";
			}
			if ((Object)(object)instance.m_craftButton == (Object)null || (Object)(object)instance.m_takeAllButton == (Object)null)
			{
				return "buttons";
			}
			if ((Object)(object)instance.m_playerGrid == (Object)null || (Object)(object)instance.m_playerGrid.m_elementPrefab == (Object)null)
			{
				return "inventory slot";
			}
			return null;
		}

		public static Transform GuiRoot()
		{
			Canvas val = (((Object)(object)InventoryGui.instance != (Object)null) ? ((Component)InventoryGui.instance).GetComponentInParent<Canvas>(true) : null);
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return ((Component)val.rootCanvas).transform;
		}

		public static Window CreateWindow(Transform parent, string title, IList<string> tabs, Action<int> onTab)
		{
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04da: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e4: Expected O, but got Unknown
			//IL_04e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d0: Expected O, but got Unknown
			//IL_07e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_07fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0807: Unknown result type (might be due to invalid IL or missing references)
			//IL_080f: Unknown result type (might be due to invalid IL or missing references)
			//IL_081b: Unknown result type (might be due to invalid IL or missing references)
			//IL_08d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_08e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_08ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_08f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0861: Unknown result type (might be due to invalid IL or missing references)
			//IL_086b: Expected O, but got Unknown
			//IL_0866: Unknown result type (might be due to invalid IL or missing references)
			//IL_086b: Unknown result type (might be due to invalid IL or missing references)
			//IL_087b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0885: Expected O, but got Unknown
			//IL_0880: Unknown result type (might be due to invalid IL or missing references)
			//IL_0885: Unknown result type (might be due to invalid IL or missing references)
			//IL_08bd: 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_0730: Unknown result type (might be due to invalid IL or missing references)
			//IL_073a: Expected O, but got Unknown
			//IL_0749: Unknown result type (might be due to invalid IL or missing references)
			//IL_0753: Expected O, but got Unknown
			InventoryGui instance = InventoryGui.instance;
			RectTransform source = instance.m_crafting;
			var anon = new
			{
				Title = PathOf((Component)(object)instance.m_craftingStationName),
				Icon = PathOf((Component)(object)instance.m_craftingStationIcon),
				Level = PathOf((Component)(object)instance.m_craftingStationLevelRoot),
				LevelText = PathOf((Component)(object)instance.m_craftingStationLevel),
				Tabs = new string[2]
				{
					PathOf((Component)(object)instance.m_tabCraft),
					PathOf((Component)(object)instance.m_tabUpgrade)
				},
				List = TopOf((Component)(object)instance.m_recipeListRoot),
				ListRoot = PathOf((Component)(object)instance.m_recipeListRoot),
				Details = TopOf((Component)(object)instance.m_recipeName),
				DetailsIcon = PathOf((Component)(object)instance.m_recipeIcon),
				DetailsName = PathOf((Component)(object)instance.m_recipeName),
				DetailsText = PathOf((Component)(object)instance.m_recipeDecription),
				DetailsFooter = PathOf((Component)(object)instance.m_itemCraftType),
				Requirements = instance.m_recipeRequirementList.Select((GameObject r) => (!((Object)(object)r != (Object)null)) ? null : PathFrom((Transform)(object)source, r.transform)).ToArray(),
				RequirementLevel = PathOf((Component)(object)instance.m_minStationLevelText),
				RequirementLevelIcon = PathOf((Component)(object)instance.m_minStationLevelIcon),
				Action = PathOf((Component)(object)instance.m_craftButton),
				Hidden = new string[4]
				{
					PathOf((Component)(object)instance.m_variantButton),
					PathOf((Component)(object)instance.m_qualityPanel),
					PathOf((Component)(object)instance.m_craftProgressPanel),
					PathOf((Component)(object)instance.m_upgradeItemName)?.Split('/').Take(2).Aggregate((string a, string b) => a + "/" + b)
				},
				Removed = new string[2]
				{
					TopOf((Component)(object)instance.m_repairButton),
					TopOf((Component)(object)instance.m_repairPanel)
				}
			};
			Rect rect = source.rect;
			Vector2 size = ((Rect)(ref rect)).size;
			GameObject val = CloneInactive(((Component)source).gameObject);
			((Object)val).name = "fjordfolk_window";
			HashSet<string> hashSet = new HashSet<string>(from p in new string[5] { anon.Title, anon.Icon, anon.Level, anon.List, anon.Details }.Concat(anon.Tabs)
				where !string.IsNullOrEmpty(p)
				select p.Split('/')[0]);
			foreach (Transform item in ((IEnumerable)val.transform).Cast<Transform>().ToList())
			{
				Image component = ((Component)item).GetComponent<Image>();
				Sprite val2 = ((component != null) ? component.sprite : null);
				bool num = (Object)(object)val2 != (Object)null && ((Object)val2).name.Contains("repair");
				bool flag = !((Component)item).gameObject.activeSelf && !hashSet.Contains(((Object)item).name);
				if (num || flag || anon.Removed.Contains(((Object)item).name))
				{
					Object.DestroyImmediate((Object)(object)((Component)item).gameObject);
				}
			}
			foreach (string item2 in new string[14]
			{
				anon.Title, anon.Icon, anon.Level, anon.LevelText, anon.List, anon.ListRoot, anon.Details, anon.DetailsIcon, anon.DetailsName, anon.DetailsText,
				anon.DetailsFooter, anon.RequirementLevel, anon.RequirementLevelIcon, anon.Action
			}.Concat(anon.Tabs).Concat(anon.Requirements))
			{
				SwitchOn(val, item2);
			}
			foreach (string item3 in anon.Hidden.Where((string p) => !string.IsNullOrEmpty(p)))
			{
				Transform obj = val.transform.Find(item3);
				if (obj != null)
				{
					((Component)obj).gameObject.SetActive(false);
				}
			}
			RectTransform val3 = Find<RectTransform>(val, anon.ListRoot);
			if ((Object)(object)val3 != (Object)null)
			{
				foreach (Transform item4 in ((IEnumerable)val3).Cast<Transform>().ToList())
				{
					Object.DestroyImmediate((Object)(object)((Component)item4).gameObject);
				}
			}
			Strip(val);
			Window obj2 = new Window
			{
				Root = (RectTransform)val.transform,
				Width = size.x,
				Title = Find<TMP_Text>(val, anon.Title),
				Icon = Find<Image>(val, anon.Icon),
				LevelText = Find<TMP_Text>(val, anon.LevelText),
				LevelTooltip = Find<UITooltip>(val, anon.Level)
			};
			Transform obj3 = val.transform.Find(anon.List ?? "");
			obj2.List = ((obj3 != null) ? ((Component)obj3).gameObject : null);
			obj2.ListRoot = val3;
			obj2.ListSpacing = ((instance.m_recipeListSpace > 1f) ? instance.m_recipeListSpace : 32f);
			Transform obj4 = val.transform.Find(anon.Details ?? "");
			obj2.Details = ((obj4 != null) ? ((Component)obj4).gameObject : null);
			obj2.DetailsIcon = Find<Image>(val, anon.DetailsIcon);
			obj2.DetailsName = Find<TMP_Text>(val, anon.DetailsName);
			obj2.DetailsText = Find<TMP_Text>(val, anon.DetailsText);
			obj2.DetailsFooter = Find<TMP_Text>(val, anon.DetailsFooter);
			obj2.RequirementLevel = Find<TMP_Text>(val, anon.RequirementLevel);
			obj2.RequirementLevelTooltip = Find<UITooltip>(val, anon.RequirementLevelIcon);
			obj2.ActionButton = Find<Button>(val, anon.Action);
			Window window = obj2;
			string[] requirements = anon.Requirements;
			foreach (string path in requirements)
			{
				RectTransform val4 = Find<RectTransform>(val, path);
				if ((Object)(object)val4 != (Object)null)
				{
					window.Requirements.Add(TileOf(((Component)val4).gameObject));
				}
			}
			if ((Object)(object)window.Title != (Object)null)
			{
				window.Title.text = title;
			}
			if ((Object)(object)window.ActionButton != (Object)null)
			{
				window.ActionButton.onClick = new ButtonClickedEvent();
			}
			for (int num3 = 0; num3 < anon.Tabs.Length; num3++)
			{
				Button val5 = Find<Button>(val, anon.Tabs[num3]);
				if ((Object)(object)val5 == (Object)null)
				{
					continue;
				}
				if (tabs == null || num3 >= tabs.Count)
				{
					((Component)val5).gameObject.SetActive(false);
					continue;
				}
				int index = num3;
				val5.onClick = new ButtonClickedEvent();
				((UnityEvent)val5.onClick).AddListener((UnityAction)delegate
				{
					FjordFolkPlugin.Guard("VanillaUi.Tab", delegate
					{
						onTab(index);
					});
				});
				Transform obj5 = ((Component)val5).transform.Find("Text");
				TMP_Text val6 = ((obj5 != null) ? ((Component)obj5).GetComponent<TMP_Text>() : null) ?? ((Component)val5).GetComponentInChildren<TMP_Text>(true);
				if ((Object)(object)val6 != (Object)null)
				{
					val6.text = tabs[num3];
				}
				window.Tabs.Add(val5);
			}
			RectTransform root = window.Root;
			((Transform)root).SetParent(parent, false);
			Vector2 val7 = default(Vector2);
			((Vector2)(ref val7))..ctor(0.5f, 0.5f);
			root.anchorMax = val7;
			root.anchorMin = val7;
			root.pivot = new Vector2(0.5f, 0.5f);
			root.sizeDelta = size;
			root.anchoredPosition = Vector2.zero;
			((Transform)root).localScale = Vector3.one;
			val.SetActive(true);
			Canvas.ForceUpdateCanvases();
			if ((Object)(object)window.List != (Object)null && (Object)(object)window.Details != (Object)null)
			{
				Rect val8 = FromTopLeft(root, (RectTransform)window.List.transform);
				Rect val9 = FromTopLeft(root, (RectTransform)window.Details.transform);
				window.ContentArea = Rect.MinMaxRect(((Rect)(ref val8)).xMin, Mathf.Min(((Rect)(ref val8)).yMin, ((Rect)(ref val9)).yMin), ((Rect)(ref val9)).xMax, Mathf.Max(((Rect)(ref val8)).yMax, ((Rect)(ref val9)).yMax));
			}
			else
			{
				window.ContentArea = new Rect(10f, 101f, size.x - 20f, size.y - 105f);
			}
			return window;
			string PathOf(Component c)
			{
				if (!((Object)(object)c != (Object)null))
				{
					return null;
				}
				return PathFrom((Transform)(object)source, c.transform);
			}
			string TopOf(Component c)
			{
				string text = PathOf(c);
				if (text == null)
				{
					return null;
				}
				return text.Split('/')[0];
			}
		}

		public static ListEntry AddListEntry(Window window, int index, Action onClick)
		{
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: 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)
			//IL_0186: 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)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Expected O, but got Unknown
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Expected O, but got Unknown
			GameObject val = CloneInactive(InventoryGui.instance.m_recipeElementPrefab);
			((Object)val).name = "fjordfolk_listentry";
			ListEntry obj = new ListEntry
			{
				Root = val
			};
			Transform obj2 = val.transform.Find("icon");
			obj.Icon = ((obj2 != null) ? ((Component)obj2).GetComponent<Image>() : null);
			Transform obj3 = val.transform.Find("name");
			obj.Name = ((obj3 != null) ? ((Component)obj3).GetComponent<TMP_Text>() : null);
			Transform obj4 = val.transform.Find("QualityLevel");
			obj.Badge = ((obj4 != null) ? ((Component)obj4).GetComponent<TMP_Text>() : null);
			Transform obj5 = val.transform.Find("selected");
			obj.Selected = ((obj5 != null) ? ((Component)obj5).gameObject : null);
			obj.Button = val.GetComponent<Button>();
			ListEntry listEntry = obj;
			Transform obj6 = val.transform.Find("Durability");
			if (obj6 != null)
			{
				((Component)obj6).gameObject.SetActive(false);
			}
			GameObject selected = listEntry.Selected;
			if (selected != null)
			{
				selected.SetActive(false);
			}
			Strip(val);
			if ((Object)(object)listEntry.Button != (Object)null)
			{
				listEntry.Button.onClick = new ButtonClickedEvent();
				((UnityEvent)listEntry.Button.onClick).AddListener((UnityAction)delegate
				{
					FjordFolkPlugin.Guard("VanillaUi.ListEntry", onClick.Invoke);
				});
			}
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent((Transform)(object)window.ListRoot, false);
			val2.anchoredPosition = new Vector2(0f, (float)(-index) * window.ListSpacing);
			val.SetActive(true);
			float num = (float)(index + 1) * window.ListSpacing;
			Rect rect = window.ListRoot.rect;
			if (((Rect)(ref rect)).height < num)
			{
				window.ListRoot.SetSizeWithCurrentAnchors((Axis)1, num);
			}
			return listEntry;
		}

		public static Image Panel(Transform parent, float x, float y, float width, float height)
		{
			//IL_004c: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Expected O, but got Unknown
			Image component = ((Component)InventoryGui.instance.m_recipeName.transform.parent).GetComponent<Image>();
			GameObject val = new GameObject("fjordfolk_panel", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			Image component2 = val.GetComponent<Image>();
			if ((Object)(object)component != (Object)null)
			{
				component2.sprite = component.sprite;
				component2.type = component.type;
				((Graphic)component2).color = ((Graphic)component).color;
				((Graphic)component2).material = ((Graphic)component).material;
				component2.pixelsPerUnitMultiplier = component.pixelsPerUnitMultiplier;
			}
			else
			{
				((Graphic)component2).color = new Color(0f, 0f, 0f, 0.56f);
			}
			((Graphic)component2).raycastTarget = false;
			Place((RectTransform)val.transform, parent, x, y, new Vector2(width, height));
			return component2;
		}

		public static TMP_Text Text(Transform parent, TextStyle style, string text, float x, float y, float width, float height, TextAlignmentOptions alignment = (TextAlignmentOptions)513, float size = 0f)
		{
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Expected O, but got Unknown
			InventoryGui instance = InventoryGui.instance;
			GameObject val = CloneInactive(((Component)(style switch
			{
				TextStyle.Big => instance.m_recipeName, 
				TextStyle.Header => instance.m_itemCraftType, 
				_ => instance.m_recipeDecription, 
			})).gameObject);
			((Object)val).name = "fjordfolk_text";
			foreach (Transform item in ((IEnumerable)val.transform).Cast<Transform>().ToList())
			{
				Object.DestroyImmediate((Object)(object)((Component)item).gameObject);
			}
			Strip(val);
			StripLayouts(val, includeChildren: true);
			TMP_Text component = val.GetComponent<TMP_Text>();
			component.text = text;
			component.alignment = alignment;
			component.textWrappingMode = (TextWrappingModes)1;
			component.overflowMode = (TextOverflowModes)0;
			component.enableAutoSizing = false;
			component.richText = true;
			((Graphic)component).raycastTarget = false;
			component.fontSize = ((size > 0f) ? size : (style switch
			{
				TextStyle.Big => 30f, 
				TextStyle.Header => 20f, 
				_ => 17f, 
			}));
			Place((RectTransform)val.transform, parent, x, y, new Vector2(width, height));
			val.SetActive(true);
			return component;
		}

		public static Button Button(Transform parent, string label, float x, float y, float width, float height, Action onClick)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			//IL_00bb: 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_00d1: Expected O, but got Unknown
			GameObject val = CloneInactive(((Component)InventoryGui.instance.m_takeAllButton).gameObject);
			((Object)val).name = "fjordfolk_button";
			Strip(val);
			StripLayouts(val, includeChildren: true);
			Button component = val.GetComponent<Button>();
			component.onClick = new ButtonClickedEvent();
			((UnityEvent)component.onClick).AddListener((UnityAction)delegate
			{
				FjordFolkPlugin.Guard("VanillaUi.Button " + label, onClick.Invoke);
			});
			((Selectable)component).interactable = true;
			Transform obj = val.transform.Find("Text");
			TMP_Text val2 = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null) ?? val.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)val2 != (Object)null)
			{
				val2.text = label;
				val2.textWrappingMode = (TextWrappingModes)0;
			}
			Place((RectTransform)val.transform, parent, x, y, new Vector2(width, height));
			val.SetActive(true);
			return component;
		}

		public static void SetButtonLabel(Button button, string label)
		{
			object obj;
			if (!((Object)(object)button != (Object)null))
			{
				obj = null;
			}
			else
			{
				Transform obj2 = ((Component)button).transform.Find("Text");
				obj = ((obj2 != null) ? ((Component)obj2).GetComponent<TMP_Text>() : null) ?? ((Component)button).GetComponentInChildren<TMP_Text>(true);
			}
			TMP_Text val = (TMP_Text)obj;
			if ((Object)(object)val != (Object)null)
			{
				val.text = label;
			}
		}

		public static UITooltip TooltipOf(Component c)
		{
			if (!((Object)(object)c != (Object)null))
			{
				return null;
			}
			return c.GetComponentInChildren<UITooltip>(true);
		}

		public static void SetTooltip(UITooltip tooltip, string topic, string text)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)tooltip != (Object)null)
			{
				tooltip.Set(topic, text, (RectTransform)null, Vector2.zero);
			}
		}

		public static Slot InventorySlot(Transform parent, float x, float y, float size, Action onClick)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Expected O, but got Unknown
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Expected O, but got Unknown
			GameObject val = CloneInactive(InventoryGui.instance.m_playerGrid.m_elementPrefab);
			((Object)val).name = "fjordfolk_slot";
			InventoryElement component = val.GetComponent<InventoryElement>();
			Slot slot = new Slot
			{
				Rect = (RectTransform)val.transform,
				Icon = (((Object)(object)component != (Object)null) ? component.m_icon : null),
				Amount = (((Object)(object)component != (Object)null) ? component.m_amount : null),
				Selected = (((Object)(object)component != (Object)null) ? component.m_selected : null),
				Button = (((Object)(object)component != (Object)null && (Object)(object)component.m_button != (Object)null) ? component.m_button : val.GetComponent<Button>()),
				Tooltip = val.GetComponentInChildren<UITooltip>(true)
			};
			if ((Object)(object)component != (Object)null)
			{
				Component[] array = (Component[])(object)new Component[7]
				{
					(Component)component.m_quality,
					(Component)component.m_equiped,
					(Component)component.m_queued,
					(Component)component.m_noteleport,
					(Component)component.m_food,
					(Component)component.m_durability,
					(Component)component.m_dropFocus
				};
				foreach (Component val2 in array)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						val2.gameObject.SetActive(false);
					}
				}
			}
			Transform obj = val.transform.Find("binding");
			if (obj != null)
			{
				((Component)obj).gameObject.SetActive(false);
			}
			GameObject selected = slot.Selected;
			if (selected != null)
			{
				selected.SetActive(false);
			}
			Strip(val);
			if ((Object)(object)slot.Button != (Object)null)
			{
				slot.Button.onClick = new ButtonClickedEvent();
				if (onClick != null)
				{
					((UnityEvent)slot.Button.onClick).AddListener((UnityAction)delegate
					{
						FjordFolkPlugin.Guard("VanillaUi.Slot", onClick.Invoke);
					});
				}
			}
			float slotNaturalSize = SlotNaturalSize;
			Place(slot.Rect, parent, x, y, new Vector2(slotNaturalSize, slotNaturalSize));
			((Transform)slot.Rect).localScale = Vector3.one * (size / slotNaturalSize);
			val.SetActive(true);
			return slot;
		}

		private static Tile TileOf(GameObject go)
		{
			Tile obj = new Tile
			{
				Root = go
			};
			Transform obj2 = go.transform.Find("res_icon");
			obj.Icon = ((obj2 != null) ? ((Component)obj2).GetComponent<Image>() : null);
			Transform obj3 = go.transform.Find("res_name");
			obj.Name = ((obj3 != null) ? ((Component)obj3).GetComponent<TMP_Text>() : null);
			Transform obj4 = go.transform.Find("res_amount");
			obj.Amount = ((obj4 != null) ? ((Component)obj4).GetComponent<TMP_Text>() : null);
			obj.Tooltip = go.GetComponent<UITooltip>();
			return obj;
		}

		public static void ShowRequirement(Tile tile, Sprite icon, string name, int have, int need, string tooltip)
		{
			//IL_0064: 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_00c3: Unknown result type (might be due to invalid IL or missing references)
			Component[] array = (Component[])(object)new Component[3]
			{
				(Component)tile.Icon,
				(Component)tile.Name,
				(Component)tile.Amount
			};
			foreach (Component obj in array)
			{
				if (obj != null)
				{
					obj.gameObject.SetActive(true);
				}
			}
			if ((Object)(object)tile.Icon != (Object)null)
			{
				tile.Icon.sprite = icon;
				((Graphic)tile.Icon).color = Color.white;
			}
			if ((Object)(object)tile.Name != (Object)null)
			{
				tile.Name.text = name;
			}
			if ((Object)(object)tile.Amount != (Object)null)
			{
				tile.Amount.text = $"{have}/{need}";
				((Graphic)tile.Amount).color = ((have >= need) ? Color.white : Red);
			}
			SetTooltip(tile.Tooltip, name, tooltip);
		}

		public static void HideRequirement(Tile tile)
		{
			Component[] array = (Component[])(object)new Component[3]
			{
				(Component)tile.Icon,
				(Component)tile.Name,
				(Component)tile.Amount
			};
			foreach (Component obj in array)
			{
				if (obj != null)
				{
					obj.gameObject.SetActive(false);
				}
			}
			SetTooltip(tile.Tooltip, "", "");
		}

		private static GameObject CloneInactive(GameObject source)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if ((Object)(object)s_holder == (Object)null)
			{
				s_holder = new GameObject("fjordfolk_ui_holder");
				s_holder.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)s_holder);
			}
			GameObject obj = Object.Instantiate<GameObject>(source, s_holder.transform, false);
			obj.SetActive(true);
			return obj;
		}

		private static void Strip(GameObject go)
		{
			UIGamePad[] componentsInChildren = go.GetComponentsInChildren<UIGamePad>(true);
			foreach (UIGamePad val in componentsInChildren)
			{
				if ((Object)(object)val.m_hint != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)val.m_hint);
				}
			}
			foreach (GameObject item in (from b in go.GetComponentsInChildren<MonoBehaviour>(true)
				where (Object)(object)b != (Object)null && ((object)b).GetType().Name == "UIInputHint"
				select ((Component)b).gameObject).Distinct().ToList())
			{
				if ((Object)(object)item != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)item);
				}
			}
			MonoBehaviour[] componentsInChildren2 = go.GetComponentsInChildren<MonoBehaviour>(true);
			foreach (MonoBehaviour val2 in componentsInChildren2)
			{
				if ((Object)(object)val2 != (Object)null && Behaviours.Contains(((object)val2).GetType().Name))
				{
					Object.DestroyImmediate((Object)(object)val2);
				}
			}
		}

		private static void StripLayouts(GameObject go, bool includeChildren)
		{
			Component[] array = (includeChildren ? go.GetComponentsInChildren<Component>(true) : go.GetComponents<Component>());
			foreach (Component val in array)
			{
				if ((Object)(object)val != (Object)null && Layouts.Contains(((object)val).GetType().Name))
				{
					Object.DestroyImmediate((Object)(object)val);
				}
			}
		}

		public static void Place(RectTransform rect, Transform parent, float x, float y, Vector2 size)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_0048: 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)
			((Transform)rect).SetParent(parent, false);
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0f, 1f);
			rect.anchorMax = val;
			rect.anchorMin = val;
			rect.pivot = new Vector2(0f, 1f);
			rect.sizeDelta = size;
			rect.anchoredPosition = new Vector2(x, 0f - y);
			((Transform)rect).localScale = Vector3.one;
		}

		public static RectTransform Group(Transform parent, string name, float x, float y, float width, float height)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: 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_0035: Expected O, but got Unknown
			//IL_0036: Expected O, but got Unknown
			RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) }).transform;
			Place(val, parent, x, y, new Vector2(width, height));
			return val;
		}

		private static Rect FromTopLeft(RectTransform root, RectTransform child)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			child.GetWorldCorners(array);
			Rect rect = root.rect;
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(float.MaxValue, float.MaxValue);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(float.MinValue, float.MinValue);
			Vector3[] array2 = array;
			Vector2 val5 = default(Vector2);
			foreach (Vector3 val3 in array2)
			{
				Vector3 val4 = ((Transform)root).InverseTransformPoint(val3);
				((Vector2)(ref val5))..ctor(val4.x - ((Rect)(ref rect)).xMin, ((Rect)(ref rect)).yMax - val4.y);
				val = Vector2.Min(val, val5);
				val2 = Vector2.Max(val2, val5);
			}
			return Rect.MinMaxRect(val.x, val.y, val2.x, val2.y);
		}

		private static void SwitchOn(GameObject root, string path)
		{
			if (string.IsNullOrEmpty(path))
			{
				return;
			}
			Transform val = root.transform.Find(path);
			Transform val2 = val;
			while ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)root.transform)
			{
				((Component)val2).gameObject.SetActive(true);
				val2 = val2.parent;
			}
			if (!((Object)(object)val == (Object)null))
			{
				Graphic[] components = ((Component)val).GetComponents<Graphic>();
				for (int i = 0; i < components.Length; i++)
				{
					((Behaviour)components[i]).enabled = true;
				}
			}
		}

		private static T Find<T>(GameObject root, string path) where T : Component
		{
			if (string.IsNullOrEmpty(path))
			{
				return default(T);
			}
			Transform val = root.transform.Find(path);
			if (!((Object)(object)val != (Object)null))
			{
				return default(T);
			}
			return ((Component)val).GetComponent<T>();
		}

		private static Vector2 SizeOf(RectTransform rect, Vector2 fallback)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_0027: 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_0047: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)rect == (Object)null)
			{
				return fallback;
			}
			Rect rect2 = rect.rect;
			Vector2 val = ((Rect)(ref rect2)).size;
			if (val.x <= 1f || val.y <= 1f)
			{
				val = ((rect.anchorMin == rect.anchorMax) ? rect.sizeDelta : fallback);
			}
			return new Vector2((val.x > 1f) ? val.x : fallback.x, (val.y > 1f) ? val.y : fallback.y);
		}

		private static string PathFrom(Transform root, Transform target)
		{
			if ((Object)(object)target == (Object)null)
			{
				return null;
			}
			List<string> list = new List<string>();
			Transform val = target;
			while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
			{
				list.Add(((Object)val).name);
				val = val.parent;
			}
			list.Reverse();
			return string.Join("/", list);
		}

		public static void DumpOnce(Transform ours)
		{
			if (!s_dumped)
			{
				s_dumped = true;
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine($"# UI dump {DateTime.Now:yyyy-MM-dd HH:mm:ss}, screen {Screen.width}x{Screen.height}");
				Canvas componentInParent = ((Component)ours).GetComponentInParent<Canvas>();
				if ((Object)(object)componentInParent != (Object)null)
				{
					stringBuilder.AppendLine($"# canvas {((Object)componentInParent).name} scale {componentInParent.scaleFactor:0.###}");
				}
				stringBuilder.AppendLine().AppendLine("== our window");
				Describe(stringBuilder, ours, 0);
				string text = Path.Combine(Paths.ConfigPath, "fjordfolk_ui_dump.txt");
				File.WriteAllText(text, stringBuilder.ToString(), Encoding.UTF8);
				FjordFolkPlugin.Log.LogDebug((object)("UI layout written to " + text));
			}
		}

		private static void Describe(StringBuilder sb, Transform t, int depth)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: 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)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0318: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Expected O, but got Unknown
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			if (depth > 9)
			{
				return;
			}
			StringBuilder stringBuilder = new StringBuilder(new string(' ', depth * 2) + ((Object)t).name + (((Component)t).gameObject.activeSelf ? "" : " (off)"));
			RectTransform val = (RectTransform)(object)((t is RectTransform) ? t : null);
			if (val != null)
			{
				object[] array = new object[4];
				Rect rect = val.rect;
				array[0] = ((Rect)(ref rect)).width;
				rect = val.rect;
				array[1] = ((Rect)(ref rect)).height;
				array[2] = val.anchoredPosition.x;
				array[3] = val.anchoredPosition.y;
				stringBuilder.Append(string.Format(" rect={0:0}x{1:0} pos={2:0},{3:0} ", array) + $"anchors={val.anchorMin.x:0.##},{val.anchorMin.y:0.##}-{val.anchorMax.x:0.##},{val.anchorMax.y:0.##} pivot={val.pivot.x:0.##},{val.pivot.y:0.##}");
				if (((Transform)val).localScale != Vector3.one)
				{
					stringBuilder.Append($" scale={((Transform)val).localScale.x:0.##}");
				}
			}
			IEnumerable<string> values = from c in ((Component)t).GetComponents<Component>()
				where (Object)(object)c != (Object)null && !(c is Transform)
				select ((object)c).GetType().Name;
			stringBuilder.Append(" [").Append(string.Join(",", values)).Append(']');
			TMP_Text component = ((Component)t).GetComponent<TMP_Text>();
			if ((Object)(object)component != (Object)null)
			{
				string text = component.text ?? "";
				string arg = ((text.Length > 40) ? text.Substring(0, 40) : text).Replace("\n", " ");
				TMP_FontAsset font = component.font;
				stringBuilder.Append($" text='{arg}' font={((font != null) ? ((Object)font).name : null)} size={component.fontSize:0.#}" + string.Format("{0} color=#{1} align={2}", component.enableAutoSizing ? $" auto {component.fontSizeMin:0}-{component.fontSizeMax:0}" : "", ColorUtility.ToHtmlStringRGBA(((Graphic)component).color), component.alignment));
			}
			Image component2 = ((Component)t).GetComponent<Image>();
			if ((Object)(object)component2 != (Object)null)
			{
				Sprite sprite = component2.sprite;
				stringBuilder.Append($" sprite={((sprite != null) ? ((Object)sprite).name : null)} type={component2.type} color=#{ColorUtility.ToHtmlStringRGBA(((Graphic)component2).color)}");
			}
			sb.AppendLine(stringBuilder.ToString());
			foreach (Transform item in t)
			{
				Transform val2 = item;
				if (!(((Object)val2).name == "fjordfolk_slot") || val2.GetSiblingIndex() <= 0 || !(((Object)t.GetChild(val2.GetSiblingIndex() - 1)).name == "fjordfolk_slot"))
				{
					Describe(sb, val2, depth + 1);
				}
			}
		}
	}
}
namespace FjordFolk.Fisher
{
	internal static class FisherConfig
	{
		public static ConfigEntry<float> SecondsPerCatch;

		public static ConfigEntry<int> BasketCapacity;

		public static ConfigEntry<float> MaxCatchUpSeconds;

		public static ConfigEntry<float> WaterSearchRadius;

		public static ConfigEntry<float> NoviceBaseCost;

		public static ConfigEntry<float> NoviceTierStep;

		public static ConfigEntry<float> MasterBaseCost;

		public static ConfigEntry<float> MasterTierStep;

		public static ConfigEntry<float> LuckSpread;

		public static ConfigEntry<int> WorkplaceCoins;

		public static void Bind(ConfigFile config)
		{
			SecondsPerCatch = config.Bind<float>("Fisherman.Work", "SecondsPerCatch", 120f, "Average real seconds per caught fish, jittered by ±25%.");
			BasketCapacity = config.Bind<int>("Fisherman.Work", "BasketCapacity", 60, "Fish the basket holds before he stops working.");
			MaxCatchUpSeconds = config.Bind<float>("Fisherman.Work", "MaxCatchUpSeconds", 1800f, "Longest absence that is worked off on return, like a beehive. 1800 s is one game day.");
			WaterSearchRadius = config.Bind<float>("Fisherman.Work", "WaterSearchRadius", 8f, "Horizontal distance within which water must exist to place the workplace. Height is ignored.");
			NoviceBaseCost = config.Bind<float>("Fisherman.Economy", "NoviceBaseCost", 8f, "Average coins per fish at mastery 0 for the basic bait. Mastery goes one level per biome, eight in all.");
			NoviceTierStep = config.Bind<float>("Fisherman.Economy", "NoviceTierStep", 2f, "Extra average coins per bait tier above basic, at mastery 0.");
			MasterBaseCost = config.Bind<float>("Fisherman.Economy", "MasterBaseCost", 4f, "Average coins per fish at max mastery for the basic bait.");
			MasterTierStep = config.Bind<float>("Fisherman.Economy", "MasterTierStep", 1f, "Extra average coins per bait tier above basic, at max mastery.");
			LuckSpread = config.Bind<float>("Fisherman.Economy", "LuckSpread", 0.3f, "How far a single fish's price strays from the average: 0.3 means up to ±30% (8 ± 2 for a novice, 4 ± 1 for a master), most often close to the average.");
			WorkplaceCoins = config.Bind<int>("Fisherman.Progress", "WorkplaceCoins", 300, "Coins in the workplace recipe. Takes effect after restarting the game.");
		}
	}
	internal static class FisherData
	{
		public sealed class Step
		{
			public Biome Biome;

			public string Icon;

			public (string Trophy, int Amount)[] Trophies;

			public string BiomeName
			{
				get
				{
					string text = "biome_" + ((object)Unsafe.As<Biome, Biome>(ref Biome)/*cast due to .constrained prefix*/).ToString().ToLowerInvariant();
					string text2 = ((Localization.instance != null) ? Localization.instance.Localize("$" + text) : null);
					if (!string.IsNullOrEmpty(text2) && !text2.StartsWith("["))
					{
						return text2;
					}
					return Loc.T(text);
				}
			}
		}

		public static readonly (string Bait, int Tier)[] Baits = new(string, int)[9]
		{
			("FishingBait", 0),
			("FishingBaitForest", 1),
			("FishingBaitSwamp", 2),
			("FishingBaitCave", 3),
			("FishingBaitPlains", 4),
			("FishingBaitOcean", 4),
			("FishingBaitMistlands", 5),
			("FishingBaitAshlands", 6),
			("FishingBaitDeepNorth", 7)
		};

		public static readonly Step[] Steps = new Step[8]
		{
			new Step
			{
				Biome = (Biome)1,
				Icon = "TrophyDeer",
				Trophies = new(string, int)[3]
				{
					("TrophyDeer", 8),
					("TrophyBoar", 4),
					("TrophyNeck", 2)
				}
			},
			new Step
			{
				Biome = (Biome)8,
				Icon = "TrophyGreydwarf",
				Trophies = new(string, int)[3]
				{
					("TrophyGreydwarf", 8),
					("TrophySkeleton", 4),
					("TrophyGreydwarfBrute", 2)
				}
			},
			new Step
			{
				Biome = (Biome)2,
				Icon = "TrophyDraugr",
				Trophies = new(string, int)[3]
				{
					("TrophyDraugr", 8),
					("TrophyBlob", 4),
					("TrophyLeech", 2)
				}
			},
			new Step
			{
				Biome = (Biome)4,
				Icon = "TrophyWolf",
				Trophies = new(string, int)[3]
				{
					("TrophyWolf", 8),
					("TrophyHatchling", 4),
					("TrophyFenring", 2)
				}
			},
			new Step
			{
				Biome = (Biome)16,
				Icon = "TrophyGoblin",
				Trophies = new(string, int)[3]
				{
					("TrophyGoblin", 8),
					("TrophyLox", 4),
					("TrophyDeathsquito", 2)
				}
			},
			new Step
			{
				Biome = (Biome)512,
				Icon = "TrophySeeker",
				Trophies = new(string, int)[3]
				{
					("TrophySeeker", 8),
					("TrophyHare", 4),
					("TrophyTick", 2)
				}
			},
			new Step
			{
				Biome = (Biome)32,
				Icon = "TrophyCharredMelee",
				Trophies = new(string, int)[3]
				{
					("TrophyCharredMelee", 8),
					("TrophyAsksvin", 4),
					("TrophyVolture", 2)
				}
			},
			new Step
			{
				Biome = (Biome)64,
				Icon = "TrophyMoose",
				Trophies = new(string, int)[3]
				{
					("TrophyDeerWhite", 8),
					("TrophySeal", 4),
					("TrophyMoose", 2)
				}
			}
		};

		private static readonly Dictionary<string, string> s_baitToFish = new Dictionary<string, string>();

		private static bool s_resolved;

		public static int MaxLevel => Steps.Length;

		public static string Rank(int level)
		{
			return Loc.T("rank_" + Mathf.Clamp(level, 0, MaxLevel));
		}

		public static int TierOfBait(string bait)
		{
			(string, int)[] baits = Baits;
			for (int i = 0; i < baits.Length; i++)
			{
				(string, int) tuple = baits[i];
				if (tuple.Item1 == bait)
				{
					return tuple.Item2;
				}
			}
			return 0;
		}

		public static string FishForBait(string bait)
		{
			EnsureResolved();
			if (bait == null || !s_baitToFish.TryGetValue(bait, out var value))
			{
				return null;
			}
			return value;
		}

		public static IEnumerable<string> AllFish()
		{
			EnsureResolved();
			return (from b in Baits
				select FishForBait(b.Bait) into f
				where f != null
				select f).Distinct();
		}

		public static float AveragePrice(int level, int baitTier)
		{
			float num = Mathf.Clamp01((float)level / (float)MaxLevel);
			float num2 = Mathf.Lerp(FisherConfig.NoviceBaseCost.Value, FisherConfig.MasterBaseCost.Value, num);
			float num3 = Mathf.Lerp(FisherConfig.NoviceTierStep.Value, FisherConfig.MasterTierStep.Value, num);
			return num2 + num3 * (float)baitTier;
		}

		public static int FeeDiscountPercent(int level)
		{
			float num = AveragePrice(0, 0);
			if (!(num <= 0f))
			{
				return Mathf.RoundToInt((1f - AveragePrice(level, 0) / num) * 100f);
			}
			return 0;
		}

		public static GameObject ItemPrefab(string name)
		{
			if (!((Object)(object)ObjectDB.instance != (Object)null))
			{
				return null;
			}
			return ObjectDB.instance.GetItemPrefab(name);
		}

		public static string DisplayName(string prefabName)
		{
			GameObject obj = ItemPrefab(prefabName);
			string text = ((obj != null) ? obj.GetComponent<ItemDrop>() : null)?.m_itemData?.m_shared?.m_name;
			if (text == null || Localization.instance == null)
			{
				return prefabName;
			}
			return Localization.instance.Localize(text);
		}

		public static Sprite Icon(string prefabName)
		{
			GameObject obj = ItemPrefab(prefabName);
			if (obj == null)
			{
				return null;
			}
			ItemDrop component = obj.GetComponent<ItemDrop>();
			if (component == null)
			{
				return null;
			}
			ItemData itemData = component.m_itemData;
			if (itemData == null)
			{
				return null;
			}
			return itemData.GetIcon();
		}

		private static void EnsureResolved()
		{
			if (s_resolved || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return;
			}
			s_resolved = true;
			ResolveBaits();
			List<string> list = (from n in Steps.SelectMany((Step s) => s.Trophies.Select(((string Trophy, int Amount) t) => t.Trophy).Append(s.Icon)).Distinct()
				where (Object)(object)ItemPrefab(n) == (Object)null
				select n).ToList();
			if (list.Count > 0)
			{
				FjordFolkPlugin.Log.LogWarning((object)("fisher mastery uses unknown trophies: " + string.Join(", ", list)));
			}
		}

		private static void ResolveBaits()
		{
			Dictionary<string, (string, float)> dictionary = new Dictionary<string, (string, float)>();
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				Fish val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Fish>() : null);
				if (val?.m_baits == null)
				{
					continue;
				}
				foreach (BaitSetting bait in val.m_baits)
				{
					if (!((Object)(object)bait?.m_bait == (Object)null))
					{
						string name = ((Object)bait.m_bait).name;
						if (!dictionary.TryGetValue(name, out var value) || bait.m_chance > value.Item2)
						{
							dictionary[name] = (((Object)prefab).name, bait.m_chance);
						}
					}
				}
			}
			(string, int)[] baits = Baits;
			for (int i = 0; i < baits.Length; i++)
			{
				(string, int) tuple = baits[i];
				if (dictionary.TryGetValue(tuple.Item1, out var value2))
				{
					s_baitToFish[tuple.Item1] = value2.Item1;
				}
			}
			FjordFolkPlugin.Log.LogDebug((object)("fisher bait → fish: " + string.Join(", ", Baits.Select(((string Bait, int Tier) b) => string.Format("{0}(tier {1}) → {2}", b.Bait, b.Tier, s_baitToFish.TryGetValue(b.Bait, out var value3) ? value3 : "none")))));
		}
	}
	internal sealed class FisherPanel : MonoBehaviour
	{
		private const float MaxDistance = 6f;

		private const float Inset = 14f;

		private const float Gap = 8f;

		private const string Heading = "#FFB75C";

		private const string Warning = "#FF9C4A";

		private const string Muted = "#8C8C8C";

		private static FisherPanel s_open;

		private static float s_closedAt = -999f;

		private static int s_lastTab;

		private FisherWorkplace m_place;

		private VanillaUi.Window m_window;

		private GameObject m_workPage;

		private int m_tab;

		private int m_selectedStep = -1;

		private float m_openedAt;

		private float m_nextRefresh;

		private TMP_Text m_status;

		private TMP_Text m_summary;

		private VanillaUi.Slot m_coins;

		private TMP_Text m_basketText;

		private readonly List<(string Bait, VanillaUi.Slot Slot)> m_baitSlots = new List<(string, VanillaUi.Slot)>();

		private readonly List<(string Fish, VanillaUi.Slot Slot)> m_fishSlots = new List<(string, VanillaUi.Slot)>();

		private readonly List<VanillaUi.ListEntry> m_steps = new List<VanillaUi.ListEntry>();

		public static bool IsOpen => (Object)(object)s_open != (Object)null;

		public static bool JustClosed => Time.time - s_closedAt < 0.3f;

		public static void Open(FisherWorkplace place)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)s_open != (Object)null)
			{
				s_open.Close();
			}
			string text = VanillaUi.MissingPart();
			Transform val = VanillaUi.GuiRoot() ?? (((Object)(object)GUIManager.CustomGUIFront != (Object)null) ? GUIManager.CustomGUIFront.transform : null);
			if (text != null || (Object)(object)val == (Object)null)
			{
				FjordFolkPlugin.Log.LogWarning((object)("fisher window not opened: game UI part missing (" + (text ?? "GUI canvas") + ")"));
				return;
			}
			GameObject val2 = new GameObject("fjordfolk_fisher_panel", new Type[1] { typeof(RectTransform) });
			RectTransform val3 = (RectTransform)val2.transform;
			((Transform)val3).SetParent(val, false);
			val3.anchorMin = Vector2.zero;
			val3.anchorMax = Vector2.one;
			Vector2 offsetMin = (val3.offsetMax = Vector2.zero);
			val3.offsetMin = offsetMin;
			((Transform)val3).SetAsLastSibling();
			FisherPanel panel = val2.AddComponent<FisherPanel>();
			panel.m_place = place;
			panel.m_openedAt = Time.time;
			try
			{
				panel.Build();
			}
			catch (Exception arg)
			{
				FjordFolkPlugin.Log.LogError((object)$"fisher window failed to build: {arg}");
				Object.Destroy((Object)(object)val2);
				return;
			}
			s_open = panel;
			GUIManager.BlockInput(true);
			Chat instance = Chat.instance;
			if (instance != null)
			{
				instance.ClearNpcText(((Component)place).gameObject);
			}
			if (DebugConfig.WriteUiLayout.Value)
			{
				FjordFolkPlugin.Guard("VanillaUi.DumpOnce", delegate
				{
					VanillaUi.DumpOnce((Transform)(object)panel.m_window.Root);
				});
			}
		}

		private void Close()
		{
			if ((Object)(object)s_open == (Object)(object)this)
			{
				s_open = null;
				s_closedAt = Time.time;
				GUIManager.BlockInput(false);
			}
			Object.Destroy((Object)(object)((Component)this).gameObject);
		}

		private void OnDestroy()
		{
			if ((Object)(object)s_open == (Object)(object)this)
			{
				s_open = null;
				s_closedAt = Time.time;
				GUIManager.BlockInput(false);
			}
		}

		private void LateUpdate()
		{
			//IL_0038: 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)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)m_place == (Object)null || !m_place.IsLive || (Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || Vector3.Distance(((Component)localPlayer).transform.position, ((Component)m_place).transform.position) > 6f)
			{
				Close();
				return;
			}
			if (Time.time - m_openedAt > 0.25f && (ZInput.GetKeyDown((KeyCode)27, true) || ZInput.GetButtonDown("Use")))
			{
				Close();
				return;
			}
			GameObject tooltip = UITooltip.m_tooltip;
			if ((Object)(object)tooltip != (Object)null && tooltip.activeSelf && (Object)(object)tooltip.transform.parent == (Object)(object)((Component)this).transform.parent && tooltip.transform.GetSiblingIndex() < ((Component)this).transform.GetSiblingIndex())
			{
				tooltip.transform.SetAsLastSibling();
			}
			if (Time.time >= m_nextRefresh)
			{
				m_nextRefresh = Time.time + 0.5f;
				FjordFolkPlugin.Guard("FisherPanel.Refresh", Refresh);
			}
		}

		private void Build()
		{
			m_window = VanillaUi.CreateWindow(((Component)this).transform, Loc.T("knut_name"), new string[2]
			{
				Loc.T("tab_work"),
				Loc.T("tab_upgrade")
			}, ShowTab);
			if ((Object)(object)m_window.Icon != (Object)null)
			{
				m_window.Icon.sprite = Portrait();
			}
			BuildWorkPage();
			BuildUpgradePage();
			ShowTab(s_lastTab);
		}

		private void BuildWorkPage()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0354: Unknown result type (might be due to invalid IL or missing references)
			//IL_040c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0442: Unknown result type (might be due to invalid IL or missing references)
			//IL_0491: Unknown result type (might be due to invalid IL or missing references)
			//IL_0571: Unknown result type (might be due to invalid IL or missing references)
			Rect contentArea = m_window.ContentArea;
			RectTransform val = VanillaUi.Group((Transform)(object)m_window.Root, "fjordfolk_work", ((Rect)(ref contentArea)).x, ((Rect)(ref contentArea)).y, ((Rect)(ref contentArea)).width, ((Rect)(ref contentArea)).height);
			m_workPage = ((Component)val).gameObject;
			float width = ((Rect)(ref contentArea)).width;
			float num = width - 28f;
			float slotNaturalSize = VanillaUi.SlotNaturalSize;
			Vector2 buttonSize = VanillaUi.ButtonSize;
			float num2 = 0f;
			float num3 = 64f;
			VanillaUi.Panel((Transform)(object)val, 0f, num2, width, num3);
			m_status = VanillaUi.Text((Transform)(object)val, VanillaUi.TextStyle.Header, "", 14f, num2 + 8f, num, 26f, (TextAlignmentOptions)513);
			m_status.textWrappingMode = (TextWrappingModes)0;
			m_status.enableAutoSizing = true;
			m_status.fontSizeMin = 12f;
			m_status.fontSizeMax = 20f;
			m_summary = VanillaUi.Text((Transform)(object)val, VanillaUi.TextStyle.Body, "", 14f, num2 + 34f, num, 24f, (TextAlignmentOptions)513, 15f);
			m_summary.textWrappingMode = (TextWrappingModes)0;
			m_summary.enableAutoSizing = true;
			m_summary.fontSizeMin = 11f;
			m_summary.fontSizeMax = 15f;
			num2 += num3 + 8f;
			num3 = 40f + slotNaturalSize + 14f;
			VanillaUi.Panel((Transform)(object)val, 0f, num2, width, num3);
			Header((Transform)(object)val, Loc.T("wage"), Loc.T("wage_hint"), num2, num);
			m_coins = VanillaUi.InventorySlot((Transform)(object)val, 14f, num2 + 40f, slotNaturalSize, null);
			VanillaUi.SetTooltip(m_coins.Tooltip, Loc.T("wage_tip_title"), Loc.T("wage_tip"));
			float num4 = 14f + slotNaturalSize + 14f;
			float y = num2 + 40f + (slotNaturalSize - buttonSize.y) / 2f;
			float width2 = width - 14f - num4 - 246f;
			VanillaUi.Button((Transform)(object)val, "+10", num4, y, 74f, buttonSize.y, delegate
			{
				OnGiveCoins(10);
			});
			VanillaUi.Button((Transform)(object)val, "+100", num4 + 82f, y, 74f, buttonSize.y, delegate
			{
				OnGiveCoins(100);
			});
			VanillaUi.Button((Transform)(object)val, Loc.T("btn_all"), num4 + 164f, y, 74f, buttonSize.y, delegate
			{
				OnGiveCoins(-1);
			});
			VanillaUi.Button((Transform)(object)val, Loc.T("btn_take"), num4 + 246f, y, width2, buttonSize.y, OnTakeCoins);
			num2 += num3 + 8f;
			List<string> list = (from b in FisherData.Baits
				where FisherData.FishForBait(b.Bait) != null
				select b.Bait).ToList();
			float num5 = RowSlotSize(list.Count, num);
			num3 = 40f + num5 + 10f + buttonSize.y + 12f;
			VanillaUi.Panel((Transform)(object)val, 0f, num2, width, num3);
			Header((Transform)(object)val, Loc.T("bait"), Loc.T("bait_hint"), num2, num);
			SlotRow((Transform)(object)val, list, num2 + 40f, num, num5, delegate(string bait)
			{
				OnSelectBait(bait);
			}, m_baitSlots, (string bait) => (Topic: FisherData.DisplayName(bait), Text: Loc.T("bait_tip", FisherData.DisplayName(FisherData.FishForBait(bait)))));
			float num6 = (num - 8f) / 2f;
			float y2 = num2 + 40f + num5 + 10f;
			VanillaUi.Button((Transform)(object)val, Loc.T("btn_give_bait"), 14f, y2, num6, buttonSize.y, OnGiveBait);
			VanillaUi.Button((Transform)(object)val, Loc.T("btn_take_bait"), 14f + num6 + 8f, y2, num6, buttonSize.y, OnTakeBait);
			num2 += num3 + 8f;
			List<string> list2 = FisherData.AllFish().ToList();
			float num7 = RowSlotSize(list2.Count, num);
			num3 = Mathf.Max(40f + num7 + 10f + buttonSize.y + 12f, ((Rect)(ref contentArea)).height - num2);
			VanillaUi.Panel((Transform)(object)val, 0f, num2, width, num3);
			Header((Transform)(object)val, Loc.T("catch"), null, num2, num);
			m_basketText = VanillaUi.Text((Transform)(object)val, VanillaUi.TextStyle.Body, "", 14f, num2 + 9f, num, 26f, (TextAlignmentOptions)516, 16f);
			SlotRow((Transform)(object)val, list2, num2 + 40f, num, num7, null, m_fishSlots, (string fish) => (Topic: FisherData.DisplayName(fish), Text: Loc.T("catch_tip")));
			VanillaUi.Button((Transform)(object)val, Loc.T("btn_take_catch"), 14f + (num - 260f) / 2f, num2 + 40f + num7 + 10f, 260f, buttonSize.y, OnTakeFish);
		}

		private void BuildUpgradePage()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Expected O, but got Unknown
			for (int i = 0; i < FisherData.MaxLevel; i++)
			{
				int index = i;
				m_steps.Add(VanillaUi.AddListEntry(m_window, i, delegate
				{
					m_selectedStep = index;
					Refresh();
				}));
			}
			if ((Object)(object)m_window.ActionButton != (Object)null)
			{
				((UnityEvent)m_window.ActionButton.onClick).AddListener((UnityAction)delegate
				{
					FjordFolkPlugin.Guard("FisherPanel.Upgrade", OnUpgrade);
				});
				VanillaUi.SetButtonLabel(m_window.ActionButton, Loc.T("btn_upgrade"));
			}
		}

		private static void Header(Transform page, string title, string hint, float y, float inner)
		{
			VanillaUi.Text(page, VanillaUi.TextStyle.Header, title, 14f, y + 8f, inner, 28f, (TextAlignmentOptions)513);
			if (hint != null)
			{
				VanillaUi.Text(page, VanillaUi.TextStyle.Body, hint, 14f, y + 10f, inner, 26f, (TextAlignmentOptions)516, 15f);
			}
		}

		private static float RowSlotSize(int count, float inner)
		{
			float num = Mathf.Min(VanillaUi.SlotSpacing, inner / (float)Mathf.Max(1, count));
			return Mathf.Min(VanillaUi.SlotNaturalSize, num - 4f);
		}

		private static void SlotRow(Transform page, List<string> items, float y, float inner, float size, Action<string> onClick, List<(string, VanillaUi.Slot)> into, Func<string, (string Topic, string Text)> tooltip)
		{
			float num = size + 4f;
			float num2 = 14f + (inner - num * (float)items.Count + 4f) / 2f;
			for (int i = 0; i < items.Count; i++)
			{
				string item = items[i];
				VanillaUi.Slot slot = VanillaUi.InventorySlot(page, num2 + (float)i * num, y, size, (onClick != null) ? ((Action)de