Decompiled source of Mayheim v0.3.4

plugins\ValheimMMO.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using ValheimMMO.Cities;
using ValheimMMO.Config;
using ValheimMMO.Drops;
using ValheimMMO.Dungeons;
using ValheimMMO.Hunger;
using ValheimMMO.InventorySlots;
using ValheimMMO.Items;
using ValheimMMO.Merchant;
using ValheimMMO.Progression;
using ValheimMMO.Pvp;
using ValheimMMO.Quests;
using ValheimMMO.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ValheimMMO")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.3.4.0")]
[assembly: AssemblyInformationalVersion("0.3.4")]
[assembly: AssemblyProduct("ValheimMMO")]
[assembly: AssemblyTitle("ValheimMMO")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.3.4.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 ValheimMMO
{
	[BepInPlugin("com.lucas.valheimmmo", "Mayheim", "0.3.4")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginId = "com.lucas.valheimmmo";

		public const string PluginName = "Mayheim";

		public const string PluginVersion = "0.3.4";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			((Component)this).gameObject.AddComponent<MmoUI>();
			((Component)this).gameObject.AddComponent<MerchantSellUI>();
			((Component)this).gameObject.AddComponent<QuestNpcUI>();
			((Component)this).gameObject.AddComponent<QuestTracker>();
			_harmony = new Harmony("com.lucas.valheimmmo");
			PatchIsolated();
			Log.LogInfo((object)"Mayheim v0.3.4 carregado.");
		}

		private void PatchIsolated()
		{
			int num = 0;
			int num2 = 0;
			Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(typeof(Plugin).Assembly);
			foreach (Type type in typesFromAssembly)
			{
				if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: true).Length != 0)
				{
					try
					{
						_harmony.CreateClassProcessor(type).Patch();
						num++;
					}
					catch (Exception ex)
					{
						num2++;
						Log.LogError((object)("Falha ao aplicar patch " + type.FullName + ": " + ex.Message));
					}
				}
			}
			Log.LogInfo((object)($"Patches aplicados: {num} classes" + ((num2 > 0) ? $", {num2} com falha (ver acima)" : ".")));
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace ValheimMMO.UI
{
	[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
	internal static class GameCamera_UpdateMouseCapture_Patch
	{
		private static void Postfix()
		{
			if (QuestNpcUI.IsOpen || MmoUI.PanelOpen)
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
		}
	}
	internal sealed class ClonedBar
	{
		public GameObject Root;

		public RectTransform Rect;

		public GuiBar[] Bars;

		public TMP_Text Text;

		public Animator Animator;

		public bool Alive => (Object)(object)Root != (Object)null;

		public static ClonedBar From(RectTransform source, string name, bool fixedText)
		{
			//IL_00b3: 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_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			GameObject val = Object.Instantiate<GameObject>(((Component)source).gameObject, ((Transform)source).parent);
			((Object)val).name = name;
			ClonedBar clonedBar = new ClonedBar
			{
				Root = val,
				Rect = val.GetComponent<RectTransform>(),
				Bars = val.GetComponentsInChildren<GuiBar>(true),
				Text = val.GetComponentInChildren<TMP_Text>(true),
				Animator = (val.GetComponent<Animator>() ?? val.GetComponentInChildren<Animator>(true))
			};
			if ((Object)(object)clonedBar.Text != (Object)null && fixedText)
			{
				TMP_Text text = clonedBar.Text;
				text.enableAutoSizing = false;
				text.fontSize = 15f;
				text.textWrappingMode = (TextWrappingModes)0;
				text.overflowMode = (TextOverflowModes)0;
				text.alignment = (TextAlignmentOptions)514;
				((Graphic)text).color = Color.white;
				text.fontStyle = (FontStyles)(text.fontStyle | 1);
				RectTransform rectTransform = text.rectTransform;
				rectTransform.anchorMin = Vector2.zero;
				rectTransform.anchorMax = Vector2.one;
				rectTransform.offsetMin = new Vector2(8f, 0f);
				rectTransform.offsetMax = new Vector2(-8f, 0f);
			}
			val.SetActive(true);
			return clonedBar;
		}

		public void SetVisible(bool visible)
		{
			if (Alive)
			{
				if (Root.activeSelf != visible)
				{
					Root.SetActive(visible);
				}
				if (visible && (Object)(object)Animator != (Object)null)
				{
					Animator.SetBool("Visible", true);
				}
			}
		}

		public void SetLength(float size, float borderBuffer)
		{
			if (Alive)
			{
				size = Mathf.Ceil(size);
				Rect.SetSizeWithCurrentAnchors((Axis)0, size + borderBuffer);
				GuiBar[] bars = Bars;
				for (int i = 0; i < bars.Length; i++)
				{
					bars[i].SetWidth(size);
				}
			}
		}

		public void SetValue(float value, float max, Color color)
		{
			//IL_0060: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (Alive)
			{
				for (int i = 0; i < Bars.Length; i++)
				{
					Bars[i].SetMaxValue(max);
					Bars[i].SetValue(Mathf.Clamp(value, 0f, max));
					Bars[i].SetColor((i == 0) ? color : (color * new Color(0.55f, 0.55f, 0.55f, 1f)));
				}
			}
		}
	}
	internal static class HudBars
	{
		private static ClonedBar _xp;

		private static readonly Color XpColor = new Color(0.42f, 0.55f, 0.95f);

		internal static void Update(Hud hud)
		{
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)hud == (Object)null || (Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			PlayerProgress playerProgress = PlayerProgress.Get(localPlayer);
			if (playerProgress == null)
			{
				return;
			}
			bool flag = ModConfig.ShowXpBar.Value && !InventoryGui.IsVisible();
			if (_xp == null || !_xp.Alive)
			{
				if (!flag)
				{
					return;
				}
				_xp = ClonedBar.From(hud.m_staminaBar2Root, "MMO_XpBar", fixedText: true);
				if (_xp == null)
				{
					return;
				}
			}
			_xp.SetVisible(flag);
			if (flag)
			{
				_xp.Rect.anchoredPosition = new Vector2(ModConfig.XpBarOffsetX.Value, ModConfig.XpBarOffsetY.Value);
				_xp.SetLength(Mathf.Max(120f, ModConfig.XpBarWidth.Value), 16f);
				bool flag2 = playerProgress.Level >= ModConfig.MaxLevel.Value;
				float num = (flag2 ? 1f : playerProgress.LevelProgress);
				_xp.SetValue(num, 1f, XpColor);
				if ((Object)(object)_xp.Text != (Object)null)
				{
					_xp.Text.text = (flag2 ? $"Lv {playerProgress.Level}   MAX" : $"Lv {playerProgress.Level}   {playerProgress.Xp} / {playerProgress.XpForNextLevel}   {num * 100f:0}%");
				}
			}
		}
	}
	internal static class HudHungerBar
	{
		private static ClonedBar _bar;

		internal static void Update(Hud hud, Player player)
		{
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)hud == (Object)null || (Object)(object)player == (Object)null || (Object)(object)hud.m_healthBarRoot == (Object)null)
			{
				return;
			}
			PlayerProgress playerProgress = PlayerProgress.Get(player);
			if (!ModConfig.ShowHungerBar.Value || !ModConfig.HungerEnabled.Value || playerProgress == null || !(playerProgress.Satiety >= 0f))
			{
				if (_bar != null)
				{
					_bar.SetVisible(visible: false);
				}
				return;
			}
			HideFoodUi(hud);
			if (_bar == null || !_bar.Alive)
			{
				_bar = ClonedBar.From(hud.m_healthBarRoot, "MMO_HungerBar", fixedText: false);
				if (_bar == null)
				{
					return;
				}
			}
			_bar.SetVisible(visible: true);
			if ((Object)(object)hud.m_foodBarRoot != (Object)null)
			{
				((Transform)_bar.Rect).position = ((Transform)hud.m_foodBarRoot).position;
				((Transform)_bar.Rect).rotation = ((Transform)hud.m_foodBarRoot).rotation;
			}
			float max = HungerSystem.Max;
			HungerState s = HungerSystem.StateOf(playerProgress.Satiety);
			_bar.SetLength(max / 25f * 32f, 0f);
			_bar.SetValue(playerProgress.Satiety, max, HungerSystem.ColorOf(s));
			if ((Object)(object)_bar.Text != (Object)null)
			{
				_bar.Text.text = Mathf.CeilToInt(playerProgress.Satiety).ToString();
			}
			if ((Object)(object)hud.m_foodIcon != (Object)null)
			{
				((Graphic)hud.m_foodIcon).color = HungerSystem.ColorOf(s);
			}
		}

		private static void HideFoodUi(Hud hud)
		{
			if (hud.m_foodBars != null)
			{
				Image[] foodBars = hud.m_foodBars;
				foreach (Image val in foodBars)
				{
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					if (((Behaviour)val).enabled)
					{
						((Behaviour)val).enabled = false;
					}
					Graphic[] componentsInChildren = ((Component)val).GetComponentsInChildren<Graphic>(true);
					foreach (Graphic val2 in componentsInChildren)
					{
						if ((Object)(object)val2 != (Object)null && ((Behaviour)val2).enabled)
						{
							((Behaviour)val2).enabled = false;
						}
					}
				}
			}
			if (hud.m_foodIcons != null)
			{
				Image[] foodBars = hud.m_foodIcons;
				foreach (Image val3 in foodBars)
				{
					if ((Object)(object)val3 != (Object)null && ((Component)val3).gameObject.activeSelf)
					{
						((Component)val3).gameObject.SetActive(false);
					}
				}
			}
			if (hud.m_foodTime != null)
			{
				TMP_Text[] foodTime = hud.m_foodTime;
				foreach (TMP_Text val4 in foodTime)
				{
					if ((Object)(object)val4 != (Object)null && ((Component)val4).gameObject.activeSelf)
					{
						((Component)val4).gameObject.SetActive(false);
					}
				}
			}
			if ((Object)(object)hud.m_foodBaseBar != (Object)null && ((Component)hud.m_foodBaseBar).gameObject.activeSelf)
			{
				((Component)hud.m_foodBaseBar).gameObject.SetActive(false);
			}
			if ((Object)(object)hud.m_foodText != (Object)null && ((Component)hud.m_foodText).gameObject.activeSelf)
			{
				((Component)hud.m_foodText).gameObject.SetActive(false);
			}
			if ((Object)(object)hud.m_foodBarRoot != (Object)null && ((Component)hud.m_foodBarRoot).gameObject.activeSelf)
			{
				((Component)hud.m_foodBarRoot).gameObject.SetActive(false);
			}
			object obj2;
			if (!((Object)(object)hud.m_healthPanel != (Object)null))
			{
				RectTransform healthBarRoot = hud.m_healthBarRoot;
				Transform obj = ((healthBarRoot != null) ? ((Transform)healthBarRoot).parent : null);
				obj2 = ((obj is RectTransform) ? obj : null);
			}
			else
			{
				obj2 = hud.m_healthPanel;
			}
			RectTransform val5 = (RectTransform)obj2;
			if ((Object)(object)val5 != (Object)null)
			{
				for (int k = 0; k < ((Transform)val5).childCount; k++)
				{
					Transform child = ((Transform)val5).GetChild(k);
					string name = ((Object)child).name;
					bool num = name.Length == 5 && name.StartsWith("food", StringComparison.OrdinalIgnoreCase) && char.IsDigit(name[4]);
					bool flag = name.StartsWith("foodicon (", StringComparison.OrdinalIgnoreCase);
					if ((num || flag) && ((Component)child).gameObject.activeSelf)
					{
						((Component)child).gameObject.SetActive(false);
					}
				}
			}
			if ((Object)(object)hud.m_foodIcon != (Object)null)
			{
				if (!((Component)hud.m_foodIcon).gameObject.activeSelf)
				{
					((Component)hud.m_foodIcon).gameObject.SetActive(true);
				}
				if (!((Behaviour)hud.m_foodIcon).enabled)
				{
					((Behaviour)hud.m_foodIcon).enabled = true;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Hud), "Update")]
	internal static class Hud_Update_BarsPatch
	{
		private static void Postfix(Hud __instance)
		{
			HudBars.Update(__instance);
		}
	}
	[HarmonyPatch(typeof(Hud), "UpdateFood")]
	internal static class Hud_UpdateFood_HungerPatch
	{
		private static void Postfix(Hud __instance, Player player)
		{
			HudHungerBar.Update(__instance, player);
		}
	}
	public class MmoUI : MonoBehaviour
	{
		internal static MmoUI Instance;

		internal static bool PanelOpen;

		private const float PanelWidth = 470f;

		private Rect _window = new Rect(80f, 80f, 470f, 0f);

		private Vector2 _equipScroll;

		private bool _showEquipList = true;

		private string _respecReason;

		private static readonly Color BgColor = new Color(0.075f, 0.06f, 0.045f, 0.94f);

		private static readonly Color BorderColor = new Color(0.72f, 0.58f, 0.3f, 1f);

		private static readonly Color TextColor = new Color(0.92f, 0.86f, 0.7f, 1f);

		private static readonly Color GoldColor = new Color(0.95f, 0.78f, 0.4f, 1f);

		private static readonly Color MutedColor = new Color(0.65f, 0.6f, 0.5f, 1f);

		private static readonly Color ItemBonusColor = new Color(1f, 0.62f, 0.2f, 1f);

		private static readonly Color ButtonColor = new Color(0.22f, 0.17f, 0.11f, 1f);

		private static readonly Color ButtonHover = new Color(0.32f, 0.25f, 0.15f, 1f);

		private static readonly Color BarBg = new Color(0f, 0f, 0f, 0.6f);

		private static readonly Color XpFill = new Color(0.42f, 0.55f, 0.95f, 1f);

		private static GUISkin _skin;

		private static Texture2D _white;

		private static Font _norse;

		private static bool _fontSearched;

		private static string Gold => ColorUtility.ToHtmlStringRGB(GoldColor);

		private static string Muted => ColorUtility.ToHtmlStringRGB(MutedColor);

		private static string Bonus => ColorUtility.ToHtmlStringRGB(ItemBonusColor);

		private static Texture2D White
		{
			get
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_white == (Object)null)
				{
					_white = Solid(Color.white);
				}
				return _white;
			}
		}

		private static Font NorseFont
		{
			get
			{
				if (_fontSearched)
				{
					return _norse;
				}
				_fontSearched = true;
				try
				{
					Font[] array = Resources.FindObjectsOfTypeAll<Font>();
					foreach (Font val in array)
					{
						if ((Object)(object)val != (Object)null && ((Object)val).name.IndexOf("norse", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							_norse = val;
							break;
						}
					}
				}
				catch
				{
				}
				return _norse;
			}
		}

		internal static Texture2D WhiteTex => White;

		internal static Color GoldC => GoldColor;

		internal static Color MutedC => MutedColor;

		internal static Color BorderC => BorderColor;

		internal static Color BonusC => ItemBonusColor;

		internal static GUISkin Skin
		{
			get
			{
				//IL_0034: 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_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: Expected O, but got Unknown
				//IL_004c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0054: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Expected O, but got Unknown
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d3: Expected O, but got Unknown
				//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
				//IL_0108: Expected O, but got Unknown
				//IL_0113: Unknown result type (might be due to invalid IL or missing references)
				//IL_0139: Unknown result type (might be due to invalid IL or missing references)
				//IL_013e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0146: Unknown result type (might be due to invalid IL or missing references)
				//IL_0152: Expected O, but got Unknown
				//IL_015d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0162: Unknown result type (might be due to invalid IL or missing references)
				//IL_017f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0184: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
				//IL_0201: Unknown result type (might be due to invalid IL or missing references)
				//IL_020b: Expected O, but got Unknown
				//IL_0227: Unknown result type (might be due to invalid IL or missing references)
				//IL_0231: Expected O, but got Unknown
				//IL_0238: Unknown result type (might be due to invalid IL or missing references)
				//IL_0242: Expected O, but got Unknown
				//IL_0249: Unknown result type (might be due to invalid IL or missing references)
				//IL_0253: Expected O, but got Unknown
				//IL_025e: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_skin != (Object)null)
				{
					return _skin;
				}
				GUISkin val = ScriptableObject.CreateInstance<GUISkin>();
				((Object)val).hideFlags = (HideFlags)61;
				GUISkin skin = GUI.skin;
				Font norseFont = NorseFont;
				val.window = new GUIStyle(skin.window)
				{
					padding = new RectOffset(16, 16, 28, 14),
					fontSize = 16,
					alignment = (TextAnchor)1
				};
				Texture2D background = Bordered(BgColor, BorderColor);
				val.window.normal.background = background;
				val.window.onNormal.background = background;
				val.window.normal.textColor = GoldColor;
				val.window.onNormal.textColor = GoldColor;
				val.window.border = new RectOffset(3, 3, 3, 3);
				if ((Object)(object)norseFont != (Object)null)
				{
					val.window.font = norseFont;
				}
				val.label = new GUIStyle(skin.label)
				{
					fontSize = 14,
					richText = true
				};
				val.label.normal.textColor = TextColor;
				if ((Object)(object)norseFont != (Object)null)
				{
					val.label.font = norseFont;
				}
				val.button = new GUIStyle(skin.button)
				{
					fontSize = 14,
					richText = true
				};
				val.button.normal.background = Bordered(ButtonColor, BorderColor, 12, 1);
				val.button.hover.background = Bordered(ButtonHover, GoldColor, 12, 1);
				val.button.active.background = Bordered(ButtonHover, GoldColor, 12, 1);
				val.button.normal.textColor = TextColor;
				val.button.hover.textColor = GoldColor;
				val.button.active.textColor = GoldColor;
				val.button.border = new RectOffset(2, 2, 2, 2);
				if ((Object)(object)norseFont != (Object)null)
				{
					val.button.font = norseFont;
				}
				val.scrollView = new GUIStyle(skin.scrollView);
				val.verticalScrollbar = new GUIStyle(skin.verticalScrollbar);
				val.verticalScrollbarThumb = new GUIStyle(skin.verticalScrollbarThumb);
				val.verticalScrollbarThumb.normal.background = Solid(BorderColor);
				_skin = val;
				return _skin;
			}
		}

		private static bool AttachedToInventory
		{
			get
			{
				if (ModConfig.PanelOpensWithInventory.Value && InventoryGui.IsVisible())
				{
					return !PanelOpen;
				}
				return false;
			}
		}

		internal static bool Visible
		{
			get
			{
				if ((Object)(object)Player.m_localPlayer != (Object)null)
				{
					if (!PanelOpen)
					{
						return AttachedToInventory;
					}
					return true;
				}
				return false;
			}
		}

		private static Texture2D Solid(Color c)
		{
			//IL_0004: 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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false);
			val.SetPixel(0, 0, c);
			val.Apply();
			((Object)val).hideFlags = (HideFlags)61;
			return val;
		}

		private static Texture2D Bordered(Color fill, Color border, int size = 12, int thickness = 2)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_0036: 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)
			Texture2D val = new Texture2D(size, size, (TextureFormat)4, false);
			for (int i = 0; i < size; i++)
			{
				for (int j = 0; j < size; j++)
				{
					bool flag = j < thickness || i < thickness || j >= size - thickness || i >= size - thickness;
					val.SetPixel(j, i, flag ? border : fill);
				}
			}
			val.Apply();
			((Object)val).hideFlags = (HideFlags)61;
			return val;
		}

		private void Awake()
		{
			Instance = this;
		}

		private void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = ModConfig.OpenPanelKey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown() && CanShowUi())
			{
				PanelOpen = !PanelOpen;
			}
			if (PanelOpen && (Object)(object)Player.m_localPlayer == (Object)null)
			{
				PanelOpen = false;
			}
		}

		private static bool CanShowUi()
		{
			if ((Object)(object)Player.m_localPlayer == (Object)null)
			{
				return false;
			}
			if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
			{
				return false;
			}
			if (Console.IsVisible() || TextInput.IsVisible())
			{
				return false;
			}
			if (Menu.IsVisible() || InventoryGui.IsVisible())
			{
				return false;
			}
			return true;
		}

		private void OnGUI()
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_00c9: 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_00f7: Expected O, but got Unknown
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			if (Visible)
			{
				GUISkin skin = GUI.skin;
				Matrix4x4 matrix = GUI.matrix;
				GUI.skin = Skin;
				float num = Mathf.Clamp((float)Screen.height / 1080f, 0.75f, 2.5f);
				GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(num, num, 1f));
				float num2 = (float)Screen.width / num;
				if (AttachedToInventory)
				{
					Rect val = default(Rect);
					((Rect)(ref val))..ctor((num2 - 470f) * 0.5f, 34f, 470f, 0f);
					GUILayout.Window(((Object)this).GetInstanceID(), val, new WindowFunction(DrawPanel), "PERSONAGEM", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(470f) });
				}
				else
				{
					_window = GUILayout.Window(((Object)this).GetInstanceID(), _window, new WindowFunction(DrawPanel), "PERSONAGEM", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(470f) });
				}
				GUI.matrix = matrix;
				GUI.skin = skin;
			}
		}

		private void DrawPanel(int id)
		{
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			PlayerProgress playerProgress = PlayerProgress.Get(localPlayer);
			if (playerProgress == null)
			{
				return;
			}
			bool flag = playerProgress.Level >= ModConfig.MaxLevel.Value;
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("<size=15>" + localPlayer.GetPlayerName() + "</size>", Array.Empty<GUILayoutOption>());
			GUILayout.FlexibleSpace();
			GUILayout.Label($"<size=20><b><color=#{Gold}>Level {playerProgress.Level}</color></b></size>" + (flag ? "" : $"<size=12><color=#{Muted}> / {ModConfig.MaxLevel.Value}</color></size>"), Array.Empty<GUILayoutOption>());
			GUILayout.EndHorizontal();
			GUILayout.Space(6f);
			DrawXpBar(playerProgress, flag);
			if (ModConfig.PvpEnabled.Value)
			{
				float num = Karma.Local(localPlayer);
				string arg = ((num >= ModConfig.WantedThreshold.Value) ? "E04A3A" : Muted);
				GUILayout.Label($"<size=12><color=#{arg}>Karma {num:0.0} · {Karma.StatusName(num)}</color></size>", Array.Empty<GUILayoutOption>());
			}
			GUILayout.Space(12f);
			Separator();
			GUILayout.Space(8f);
			DrawAttributes(localPlayer, playerProgress);
			GUILayout.Space(10f);
			Separator();
			GUILayout.Space(8f);
			DrawEquipment(localPlayer);
			GUILayout.Space(10f);
			Separator();
			GUILayout.Space(8f);
			string reason;
			bool flag2 = PlayerProgress.CanRespec(localPlayer, out reason);
			GUI.enabled = ModConfig.RespecEnabled.Value && playerProgress.SpentPoints > 0 && flag2;
			if (GUILayout.Button("Redistribuir todos os pontos", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f) }))
			{
				if (playerProgress.RespecAll(localPlayer, out _respecReason))
				{
					RefreshStats(localPlayer);
					((Character)localPlayer).Message((MessageType)2, "Pontos redistribuidos", 0, (Sprite)null);
				}
				else
				{
					((Character)localPlayer).Message((MessageType)2, _respecReason, 0, (Sprite)null);
				}
			}
			GUI.enabled = true;
			if (!flag2 && ModConfig.RespecEnabled.Value)
			{
				GUILayout.Label("<size=12><color=#" + Muted + "><i>" + reason + "</i></color></size>", Array.Empty<GUILayoutOption>());
			}
			if (PanelOpen)
			{
				GUILayout.Space(6f);
				if (GUILayout.Button("Fechar", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
				{
					PanelOpen = false;
				}
				GUI.DragWindow(new Rect(0f, 0f, 10000f, 26f));
			}
		}

		private void DrawAttributes(Player player, PlayerProgress prog)
		{
			int unspentPoints = prog.UnspentPoints;
			GUILayout.Label((unspentPoints > 0) ? string.Format("<color=#{0}><b>{1}</b></color> ponto{2} para distribuir", Gold, unspentPoints, (unspentPoints == 1) ? "" : "s") : ("<color=#" + Muted + ">Nenhum ponto disponivel</color>"), Array.Empty<GUILayoutOption>());
			GUILayout.Space(4f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("<size=11><color=#" + Muted + ">ATRIBUTO</color></size>", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(126f) });
			GUILayout.Label("<size=11><color=#" + Muted + ">PONTOS</color></size>", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
			GUILayout.Space(62f);
			GUILayout.Label("<size=11><color=#" + Muted + ">ITENS</color></size>", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(48f) });
			GUILayout.FlexibleSpace();
			GUILayout.Label("<size=11><color=#" + Muted + ">EFEITO</color></size>", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(130f) });
			GUILayout.EndHorizontal();
			prog.ComputeStats(player, out var hp, out var stamina, out var eitr);
			float maxCarryWeight = player.GetMaxCarryWeight();
			int[] array = ItemBonuses.TotalEquipped((Humanoid)(object)player);
			Attr[] all = AttrInfo.All;
			foreach (Attr attr in all)
			{
				int num = (int)attr;
				GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(28f) });
				GUILayout.Label("<b>" + AttrInfo.DisplayName(attr) + "</b>", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(126f) });
				GUILayout.Label($"<size=16>{prog.Spent[num]}</size>", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(50f) });
				GUI.enabled = unspentPoints > 0;
				if (GUILayout.Button("+", (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(28f),
					GUILayout.Height(24f)
				}))
				{
					prog.TrySpend(attr, player);
					RefreshStats(player);
				}
				GUI.enabled = prog.Spent[num] > 0 && ModConfig.RespecEnabled.Value;
				if (GUILayout.Button("-", (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(28f),
					GUILayout.Height(24f)
				}))
				{
					if (!prog.TryRefund(attr, player, out _respecReason))
					{
						((Character)player).Message((MessageType)2, _respecReason, 0, (Sprite)null);
					}
					else
					{
						RefreshStats(player);
					}
				}
				GUI.enabled = true;
				GUILayout.Label((array[num] > 0) ? $"<color=#{Bonus}>+{array[num]}</color>" : ("<color=#" + Muted + ">-</color>"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(48f) });
				GUILayout.FlexibleSpace();
				GUILayout.Label("<color=#" + Muted + ">" + AttrInfo.Effect(attr) + "</color>  <b>" + ValueFor(attr, hp, stamina, eitr, maxCarryWeight) + "</b>", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(130f) });
				GUILayout.EndHorizontal();
			}
		}

		private void DrawEquipment(Player player)
		{
			//IL_04f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0525: Unknown result type (might be due to invalid IL or missing references)
			//IL_052a: Unknown result type (might be due to invalid IL or missing references)
			Inventory inventory = ((Humanoid)player).GetInventory();
			if (inventory == null)
			{
				return;
			}
			List<ItemData> equippedItems = inventory.GetEquippedItems();
			GUILayout.Label(string.Format("<b>Equipamento</b>  <size=12><color=#{0}>{1} peca{2}</color></size>", Muted, equippedItems.Count, (equippedItems.Count == 1) ? "" : "s"), Array.Empty<GUILayoutOption>());
			GUILayout.Space(2f);
			EquipmentRow.Slot[] slots = EquipmentRow.Slots;
			foreach (EquipmentRow.Slot slot in slots)
			{
				ItemData val = EquipmentRow.ItemIn(inventory, slot);
				GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f) });
				GUILayout.Label("<size=12><color=#" + Muted + ">" + slot.Name + "</color></size>", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(78f) });
				if (val == null)
				{
					GUILayout.Label("<size=12><color=#" + Muted + ">vazio</color></size>", Array.Empty<GUILayoutOption>());
					GUILayout.EndHorizontal();
					continue;
				}
				DrawIcon(val, 24f);
				GUILayout.Space(6f);
				string text = Localization.instance.Localize(val.m_shared.m_name);
				string text2 = ((val.m_shared.m_maxQuality > 1) ? $" <size=11><color=#{Muted}>q{val.m_quality}</color></size>" : "");
				string text3 = ((val.m_stack > 1) ? $" <size=11><color=#{Muted}>x{val.m_stack}</color></size>" : "");
				GUILayout.Label(text + text2 + text3, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(190f) });
				int[] bonuses = ItemBonuses.For(val);
				GUILayout.Label(ItemBonuses.Any(bonuses) ? ("<size=12><color=#" + Bonus + ">" + ItemBonuses.Describe(bonuses) + "</color></size>") : ("<size=12><color=#" + Muted + ">-</color></size>"), Array.Empty<GUILayoutOption>());
				GUILayout.FlexibleSpace();
				if (GUILayout.Button("Tirar", (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Width(52f),
					GUILayout.Height(22f)
				}))
				{
					((Humanoid)player).UnequipItem(val, true);
					RefreshStats(player);
				}
				GUILayout.EndHorizontal();
			}
			List<ItemData> list = EquipmentRow.OverflowItems(inventory);
			if (list.Count > 0)
			{
				GUILayout.Space(4f);
				GUILayout.Label($"<size=12><color=#{Muted}>Sem espaco na mochila ({list.Count}): abra espaco e clique em Guardar.</color></size>", Array.Empty<GUILayoutOption>());
				foreach (ItemData item in list)
				{
					GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f) });
					DrawIcon(item, 22f);
					GUILayout.Space(6f);
					GUILayout.Label(Localization.instance.Localize(item.m_shared.m_name), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(190f) });
					GUILayout.FlexibleSpace();
					if (GUILayout.Button("Guardar", (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Width(70f),
						GUILayout.Height(22f)
					}) && !EquipmentRow.TryStore(inventory, item))
					{
						((Character)player).Message((MessageType)2, "Mochila cheia.", 0, (Sprite)null);
					}
					if (GUILayout.Button("Equipar", (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Width(70f),
						GUILayout.Height(22f)
					}))
					{
						((Humanoid)player).EquipItem(item, true);
						RefreshStats(player);
					}
					GUILayout.EndHorizontal();
				}
			}
			GUILayout.Space(6f);
			List<ItemData> list2 = new List<ItemData>();
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (allItem != null && allItem.IsEquipable() && !allItem.m_equipped)
				{
					list2.Add(allItem);
				}
			}
			list2.Sort(delegate(ItemData a, ItemData b)
			{
				int num = SlotOrder(a).CompareTo(SlotOrder(b));
				return (num == 0) ? string.Compare(a.m_shared.m_name, b.m_shared.m_name, StringComparison.Ordinal) : num;
			});
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button(_showEquipList ? "▾  Equipar da mochila" : "▸  Equipar da mochila", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(22f) }))
			{
				_showEquipList = !_showEquipList;
			}
			GUILayout.Label(string.Format("<size=12><color=#{0}>{1} disponivel{2}</color></size>", Muted, list2.Count, (list2.Count == 1) ? "" : "is"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) });
			GUILayout.EndHorizontal();
			if (!_showEquipList || list2.Count == 0)
			{
				return;
			}
			_equipScroll = GUILayout.BeginScrollView(_equipScroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(Mathf.Min(160f, 28f * (float)list2.Count + 6f)) });
			foreach (ItemData item2 in list2)
			{
				GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(26f) });
				DrawIcon(item2, 22f);
				GUILayout.Space(6f);
				string text4 = Localization.instance.Localize(item2.m_shared.m_name);
				string text5 = ((item2.m_shared.m_maxQuality > 1) ? $" <size=11><color=#{Muted}>q{item2.m_quality}</color></size>" : "");
				int[] bonuses2 = ItemBonuses.For(item2);
				string text6 = (ItemBonuses.Any(bonuses2) ? ("  <size=12><color=#" + Bonus + ">" + ItemBonuses.Describe(bonuses2) + "</color></size>") : "");
				if (GUILayout.Button("<size=13>" + text4 + text5 + text6 + "</size>", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
				{
					((Humanoid)player).EquipItem(item2, true);
					RefreshStats(player);
				}
				GUILayout.EndHorizontal();
			}
			GUILayout.EndScrollView();
		}

		private static void DrawXpBar(PlayerProgress prog, bool atCap)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = GUILayoutUtility.GetRect(1f, 20f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			GUI.color = BorderColor;
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x - 1f, ((Rect)(ref rect)).y - 1f, ((Rect)(ref rect)).width + 2f, ((Rect)(ref rect)).height + 2f), (Texture)(object)White);
			GUI.color = BarBg;
			GUI.DrawTexture(rect, (Texture)(object)White);
			float num = (atCap ? 1f : prog.LevelProgress);
			GUI.color = XpFill;
			GUI.DrawTexture(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width * num, ((Rect)(ref rect)).height), (Texture)(object)White);
			GUI.color = Color.white;
			GUIStyle val = new GUIStyle(GUI.skin.label)
			{
				alignment = (TextAnchor)4,
				fontSize = 12,
				fontStyle = (FontStyle)1
			};
			val.normal.textColor = Color.white;
			string text = (atCap ? "LEVEL MAXIMO" : $"{prog.Xp} / {prog.XpForNextLevel} XP   ({num * 100f:0}%)");
			GUI.Label(rect, text, val);
		}

		private static void Separator()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = GUILayoutUtility.GetRect(1f, 1f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			GUI.color = new Color(BorderColor.r, BorderColor.g, BorderColor.b, 0.5f);
			GUI.DrawTexture(rect, (Texture)(object)White);
			GUI.color = Color.white;
		}

		private static void DrawIcon(ItemData item, float size)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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)
			Rect rect = GUILayoutUtility.GetRect(size, size, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Width(size),
				GUILayout.Height(size)
			});
			Sprite val = null;
			try
			{
				val = item.GetIcon();
			}
			catch
			{
			}
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val.texture == (Object)null))
			{
				Texture2D texture = val.texture;
				Rect textureRect = default(Rect);
				try
				{
					textureRect = val.textureRect;
				}
				catch
				{
					((Rect)(ref textureRect))..ctor(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height);
				}
				Rect val2 = default(Rect);
				((Rect)(ref val2))..ctor(((Rect)(ref textureRect)).x / (float)((Texture)texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)texture).height, ((Rect)(ref textureRect)).width / (float)((Texture)texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)texture).height);
				GUI.DrawTextureWithTexCoords(rect, (Texture)(object)texture, val2, true);
			}
		}

		private static int SlotOrder(ItemData item)
		{
			//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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected I4, but got Unknown
			ItemType itemType = item.m_shared.m_itemType;
			return (itemType - 3) switch
			{
				0 => 0, 
				11 => 0, 
				19 => 0, 
				1 => 0, 
				2 => 1, 
				3 => 2, 
				4 => 3, 
				8 => 4, 
				14 => 5, 
				15 => 6, 
				21 => 7, 
				12 => 8, 
				16 => 9, 
				_ => 20, 
			};
		}

		private static string SlotName(ItemData item)
		{
			//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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected I4, but got Unknown
			ItemType itemType = item.m_shared.m_itemType;
			return (itemType - 3) switch
			{
				0 => "Arma", 
				11 => "Arma 2M", 
				19 => "Arma 2M", 
				1 => "Arco", 
				2 => "Escudo", 
				3 => "Cabeca", 
				4 => "Peito", 
				8 => "Pernas", 
				14 => "Capa", 
				15 => "Utilidade", 
				21 => "Amuleto", 
				12 => "Tocha", 
				16 => "Ferramenta", 
				6 => "Municao", 
				_ => ((object)Unsafe.As<ItemType, ItemType>(ref item.m_shared.m_itemType)/*cast due to .constrained prefix*/).ToString(), 
			};
		}

		private static string ValueFor(Attr attr, float hp, float stam, float eitr, float carry)
		{
			return attr switch
			{
				Attr.Vitality => $"{hp:0}", 
				Attr.Endurance => $"{stam:0}", 
				Attr.Spirit => $"{eitr:0}", 
				Attr.Conditioning => $"{carry:0} kg", 
				_ => "", 
			};
		}

		internal static void RefreshStats(Player player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				player.UpdateFood(0f, true);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "TakeInput")]
	internal static class Player_TakeInput_Patch
	{
		private static void Postfix(ref bool __result)
		{
			if (MmoUI.PanelOpen)
			{
				__result = false;
			}
		}
	}
}
namespace ValheimMMO.Quests
{
	internal static class QuestListUI
	{
		public static void Draw(Player player, int tier, string header)
		{
			//IL_0000: 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_0016: Unknown result type (might be due to invalid IL or missing references)
			string text = ColorUtility.ToHtmlStringRGB(MmoUI.MutedC);
			string text2 = ColorUtility.ToHtmlStringRGB(MmoUI.GoldC);
			string text3 = ColorUtility.ToHtmlStringRGB(MmoUI.BonusC);
			GUILayout.Label("<size=12><color=#" + text + ">" + header + "</color></size>", Array.Empty<GUILayoutOption>());
			GUILayout.Space(6f);
			List<Quest> list = QuestSystem.TodayFor(player, tier);
			if (list.Count == 0)
			{
				GUILayout.Label("<color=#" + text + ">Sem missoes hoje.</color>", Array.Empty<GUILayoutOption>());
			}
			foreach (Quest item in list)
			{
				GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
				string text4 = (item.Claimed ? ("<color=#" + text + ">feita hoje</color>") : ((!item.Accepted) ? ("<color=#" + text + ">disponivel</color>") : (item.Complete ? ("<color=#" + text2 + ">completa - fale comigo</color>") : $"<color=#{text2}>{item.Progress}/{item.Required}</color>")));
				GUILayout.Label("<size=14><b>" + item.Title + "</b></size>   <size=12>" + text4 + "</size>", Array.Empty<GUILayoutOption>());
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label($"<size=12><color=#{text}>Recompensa:</color> <color=#{text3}>{item.GoldReward}</color> moedas, <color=#{text3}>{item.XpReward}</color> XP</size>", Array.Empty<GUILayoutOption>());
				GUILayout.FlexibleSpace();
				string message = null;
				if (item.Claimed)
				{
					GUI.enabled = false;
					GUILayout.Button("Feita hoje", (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Width(110f),
						GUILayout.Height(22f)
					});
					GUI.enabled = true;
				}
				else if (!item.Accepted)
				{
					if (GUILayout.Button("Aceitar", (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Width(110f),
						GUILayout.Height(22f)
					}))
					{
						QuestSystem.Accept(player, item, out message);
					}
				}
				else if (item.Complete)
				{
					if (GUILayout.Button("Concluir", (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Width(110f),
						GUILayout.Height(22f)
					}))
					{
						QuestSystem.Claim(player, item, out message);
					}
				}
				else
				{
					if (item.Kind == QuestKind.Deliver && GUILayout.Button("Entregar", (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Width(110f),
						GUILayout.Height(22f)
					}))
					{
						QuestSystem.Deliver(player, item, out message);
					}
					if (GUILayout.Button("Abandonar", (GUILayoutOption[])(object)new GUILayoutOption[2]
					{
						GUILayout.Width(90f),
						GUILayout.Height(22f)
					}))
					{
						QuestSystem.Abandon(player, item, out message);
					}
				}
				if (message != null)
				{
					((Character)player).Message((MessageType)2, message, 0, (Sprite)null);
				}
				GUILayout.EndHorizontal();
				GUILayout.Space(8f);
				GUILayout.EndVertical();
			}
		}
	}
	public class QuestNpcUI : MonoBehaviour
	{
		internal static bool IsOpen;

		private static int _tier;

		private const float W = 560f;

		public static void Open(int tier)
		{
			_tier = tier;
			IsOpen = true;
		}

		private void Update()
		{
			if (IsOpen && ((Object)(object)Player.m_localPlayer == (Object)null || Input.GetKeyDown((KeyCode)27)))
			{
				IsOpen = false;
			}
		}

		private void OnGUI()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			if (IsOpen && !((Object)(object)Player.m_localPlayer == (Object)null))
			{
				GUISkin skin = GUI.skin;
				Matrix4x4 matrix = GUI.matrix;
				GUI.skin = MmoUI.Skin;
				float num = Mathf.Clamp((float)Screen.height / 1080f, 0.75f, 2.5f);
				GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(num, num, 1f));
				float num2 = (float)Screen.width / num;
				CityDef cityDef = CitySystem.ByTier(_tier);
				string text = ((cityDef != null) ? ("MISSOES - " + cityDef.Name.ToUpperInvariant()) : "MISSOES");
				GUILayout.Window(((Object)this).GetInstanceID(), new Rect((num2 - 560f) * 0.5f, 120f, 560f, 0f), new WindowFunction(Draw), text, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(560f) });
				GUI.matrix = matrix;
				GUI.skin = skin;
			}
		}

		private void Draw(int id)
		{
			QuestListUI.Draw(Player.m_localPlayer, _tier, $"Dia {QuestSystem.CurrentDay()} · aceite, cumpra e volte aqui para concluir. Cada missao vale uma vez por dia; amanha troca. Recompensa sempre em ouro.");
			GUILayout.Space(4f);
			if (GUILayout.Button("Fechar", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }))
			{
				IsOpen = false;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "TakeInput")]
	internal static class Player_TakeInput_QuestNpcPatch
	{
		private static void Postfix(ref bool __result)
		{
			if (QuestNpcUI.IsOpen)
			{
				__result = false;
			}
		}
	}
	internal enum QuestKind
	{
		Kill,
		Deliver,
		DungeonBoss
	}
	internal sealed class Quest
	{
		public int Tier;

		public int Index;

		public QuestKind Kind;

		public string Target;

		public string TargetName;

		public int Required;

		public int Progress;

		public bool Accepted;

		public bool Claimed;

		public int GoldReward;

		public long XpReward;

		public bool Complete => Progress >= Required;

		public bool Active
		{
			get
			{
				if (Accepted)
				{
					return !Claimed;
				}
				return false;
			}
		}

		public string Title => Kind switch
		{
			QuestKind.Kill => $"Mate {Required}x {TargetName}", 
			QuestKind.Deliver => $"Entregue {Required}x {TargetName}", 
			QuestKind.DungeonBoss => "Derrote o boss de dungeon: " + TargetName, 
			_ => "", 
		};

		public string ShortTitle => Kind switch
		{
			QuestKind.Kill => TargetName ?? "", 
			QuestKind.Deliver => "Entregar " + TargetName, 
			QuestKind.DungeonBoss => "Boss: " + TargetName, 
			_ => "", 
		};
	}
	internal static class QuestSystem
	{
		private sealed class DayCache
		{
			public int Day;

			public List<Quest> List;
		}

		public const int MaxTier = 7;

		private static readonly string[][] KillPools = new string[7][]
		{
			new string[4] { "Greyling", "Boar", "Neck", "Deer" },
			new string[5] { "Greydwarf", "Skeleton", "Greydwarf_Shaman", "Troll", "Ghost" },
			new string[6] { "Draugr", "Blob", "Leech", "Wraith", "Abomination", "Surtling" },
			new string[5] { "Wolf", "Fenring", "Hatchling", "StoneGolem", "Ulv" },
			new string[5] { "Goblin", "Deathsquito", "Lox", "GoblinShaman", "GoblinBrute" },
			new string[5] { "Seeker", "Tick", "Gjall", "Dverger", "SeekerBrute" },
			new string[5] { "Charred_Melee", "Charred_Archer", "Asksvin", "Morgen", "Volture" }
		};

		private static readonly string[][] DeliverPools = new string[7][]
		{
			new string[6] { "Wood", "Stone", "Resin", "LeatherScraps", "RawMeat", "Raspberry" },
			new string[6] { "FineWood", "CopperOre", "TinOre", "Bronze", "TrollHide", "Coal" },
			new string[6] { "IronScrap", "Guck", "Bloodbag", "Entrails", "Turnip", "Ooze" },
			new string[6] { "WolfPelt", "Silver", "Obsidian", "FreezeGland", "Crystal", "Onion" },
			new string[6] { "BlackMetalScrap", "Barley", "Flax", "LoxPelt", "Needle", "Tar" },
			new string[6] { "Carapace", "YggdrasilWood", "Sap", "Softtissue", "BlackMarble", "Mandible" },
			new string[5] { "FlametalOreNew", "CharredBone", "Grausten", "Blackwood", "AskHide" }
		};

		private static readonly Dictionary<int, DayCache> Cache = new Dictionary<int, DayCache>();

		public static int CurrentDay()
		{
			if (!((Object)(object)EnvMan.instance != (Object)null))
			{
				return 0;
			}
			return EnvMan.instance.GetDay();
		}

		private static string KeyFor(int tier)
		{
			return $"mmo.quests.{tier}";
		}

		public static List<Quest> TodayFor(Player player, int tier)
		{
			if (!ModConfig.QuestsEnabled.Value || (Object)(object)player == (Object)null)
			{
				return new List<Quest>();
			}
			tier = Mathf.Clamp(tier, 1, KillPools.Length);
			int num = tier - 1;
			int num2 = CurrentDay();
			if (Cache.TryGetValue(tier, out var value) && value.Day == num2)
			{
				if (value.List.Count > 0 && value.List[0].Progress == 0 && !value.List[0].Accepted)
				{
					LoadProgress(player, tier, value.List);
				}
				return value.List;
			}
			Random random = new Random((int)((((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldUID() : 0) ^ ((long)num2 * 7919L) ^ ((long)tier * 104729L)));
			List<Quest> list = new List<Quest>();
			string text = PickExisting(random, KillPools[num], IsCreature);
			if (text != null)
			{
				Character component = ZNetScene.instance.GetPrefab(text).GetComponent<Character>();
				float num3 = Mathf.Max(1f, component.m_health);
				int num4 = 8 + random.Next(0, 8);
				int num5 = Mathf.CeilToInt(Mathf.Pow(num3, 0.6f) * (float)num4 * 1.5f * ModConfig.QuestRewardMultiplier.Value);
				list.Add(new Quest
				{
					Tier = tier,
					Index = 0,
					Kind = QuestKind.Kill,
					Target = text,
					TargetName = Localization.instance.Localize(component.m_name),
					Required = num4,
					GoldReward = num5,
					XpReward = (long)num5 * 3L
				});
			}
			string text2 = PickExisting(random, DeliverPools[num], IsItem);
			if (text2 != null)
			{
				int num6 = 10 + random.Next(0, 11);
				int num7 = Mathf.CeilToInt((float)(MerchantPricing.PriceOf(text2) * num6) * 1.5f * ModConfig.QuestRewardMultiplier.Value);
				list.Add(new Quest
				{
					Tier = tier,
					Index = 1,
					Kind = QuestKind.Deliver,
					Target = text2,
					TargetName = Localization.instance.Localize(ObjectDB.instance.GetItemPrefab(text2).GetComponent<ItemDrop>().m_itemData.m_shared.m_name),
					Required = num6,
					GoldReward = num7,
					XpReward = (long)num7 * 3L
				});
			}
			DungeonTier dungeonTier = DungeonBosses.TierById(Mathf.Clamp(tier, 1, DungeonBosses.Tiers.Length));
			if (dungeonTier != null)
			{
				int num8 = Mathf.CeilToInt((float)DungeonBosses.GoldFor(dungeonTier) * 0.5f * ModConfig.QuestRewardMultiplier.Value);
				list.Add(new Quest
				{
					Tier = tier,
					Index = 2,
					Kind = QuestKind.DungeonBoss,
					Target = dungeonTier.Id.ToString(),
					TargetName = dungeonTier.Title,
					Required = 1,
					GoldReward = num8,
					XpReward = (long)num8 * 3L
				});
			}
			Cache[tier] = new DayCache
			{
				Day = num2,
				List = list
			};
			LoadProgress(player, tier, list);
			return list;
		}

		public static List<Quest> Active(Player player)
		{
			List<Quest> list = new List<Quest>();
			if ((Object)(object)player == (Object)null || !ModConfig.QuestsEnabled.Value)
			{
				return list;
			}
			for (int i = 1; i <= 7; i++)
			{
				foreach (Quest item in TodayFor(player, i))
				{
					if (item.Active)
					{
						list.Add(item);
					}
				}
			}
			return list;
		}

		public static void ClearCache()
		{
			Cache.Clear();
		}

		private static bool IsCreature(string name)
		{
			ZNetScene instance = ZNetScene.instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				GameObject prefab = instance.GetPrefab(name);
				obj = ((prefab != null) ? prefab.GetComponent<Character>() : null);
			}
			return (Object)obj != (Object)null;
		}

		private static bool IsItem(string name)
		{
			ObjectDB instance = ObjectDB.instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				GameObject itemPrefab = instance.GetItemPrefab(name);
				obj = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			}
			return (Object)obj != (Object)null;
		}

		private static string PickExisting(Random rng, string[] pool, Func<string, bool> exists)
		{
			List<string> list = new List<string>();
			foreach (string text in pool)
			{
				if (exists(text))
				{
					list.Add(text);
				}
			}
			if (list.Count != 0)
			{
				return list[rng.Next(list.Count)];
			}
			return null;
		}

		private static void LoadProgress(Player player, int tier, List<Quest> quests)
		{
			foreach (Quest quest in quests)
			{
				quest.Progress = 0;
				quest.Claimed = false;
				quest.Accepted = false;
			}
			if (!player.m_customData.TryGetValue(KeyFor(tier), out var value) || string.IsNullOrEmpty(value))
			{
				return;
			}
			string[] array = value.Split('|');
			if (array.Length < 1 || !int.TryParse(array[0], out var result) || result != CurrentDay())
			{
				return;
			}
			foreach (Quest quest2 in quests)
			{
				int num = 1 + quest2.Index * 3;
				if (num + 2 < array.Length)
				{
					quest2.Accepted = array[num] == "1";
					int.TryParse(array[num + 1], out quest2.Progress);
					quest2.Claimed = array[num + 2] == "1";
				}
			}
		}

		private static void SaveProgress(Player player, int tier)
		{
			if (!Cache.TryGetValue(tier, out var value))
			{
				return;
			}
			List<Quest> list = value.List;
			List<string> list2 = new List<string> { CurrentDay().ToString(CultureInfo.InvariantCulture) };
			int idx;
			for (idx = 0; idx < 3; idx++)
			{
				Quest quest = list.Find((Quest x) => x.Index == idx);
				list2.Add((quest != null && quest.Accepted) ? "1" : "0");
				list2.Add((quest?.Progress ?? 0).ToString(CultureInfo.InvariantCulture));
				list2.Add((quest != null && quest.Claimed) ? "1" : "0");
			}
			player.m_customData[KeyFor(tier)] = string.Join("|", list2);
		}

		public static bool Accept(Player player, Quest q, out string message)
		{
			message = null;
			if (q.Accepted || q.Claimed)
			{
				return false;
			}
			int count = Active(player).Count;
			int num = Mathf.Max(1, ModConfig.QuestMaxActive.Value);
			if (count >= num)
			{
				message = $"Voce ja tem {count} missoes em andamento (maximo {num}).";
				return false;
			}
			q.Accepted = true;
			SaveProgress(player, q.Tier);
			message = "Missao aceita: " + q.Title;
			return true;
		}

		public static bool Abandon(Player player, Quest q, out string message)
		{
			message = null;
			if (!q.Active)
			{
				return false;
			}
			q.Accepted = false;
			q.Progress = 0;
			SaveProgress(player, q.Tier);
			message = "Missao abandonada.";
			return true;
		}

		public static void OnKill(string victimPrefab, int dungeonTier)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !ModConfig.QuestsEnabled.Value)
			{
				return;
			}
			for (int i = 1; i <= KillPools.Length; i++)
			{
				List<Quest> list = TodayFor(localPlayer, i);
				bool flag = false;
				foreach (Quest item in list)
				{
					if (item.Active && !item.Complete && ((item.Kind == QuestKind.Kill && item.Target == victimPrefab) || (item.Kind == QuestKind.DungeonBoss && dungeonTier > 0 && item.Target == dungeonTier.ToString())))
					{
						item.Progress++;
						flag = true;
						if (item.Complete)
						{
							((Character)localPlayer).Message((MessageType)2, "Missao completa: " + item.Title + ". Volte ao emissario.", 0, (Sprite)null);
						}
						else
						{
							((Character)localPlayer).Message((MessageType)1, $"{item.ShortTitle}: {item.Progress}/{item.Required}", 0, (Sprite)null);
						}
					}
				}
				if (flag)
				{
					SaveProgress(localPlayer, i);
				}
			}
		}

		public static bool Deliver(Player player, Quest q, out string message)
		{
			message = null;
			if (q.Kind != QuestKind.Deliver || !q.Active)
			{
				return false;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(q.Target);
			ItemDrop val = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			string name = val.m_itemData.m_shared.m_name;
			int num = Mathf.Min(inventory.CountItems(name, -1, true), q.Required - q.Progress);
			if (num <= 0)
			{
				message = "Voce nao tem esse item na mochila.";
				return false;
			}
			inventory.RemoveItem(name, num, -1, true);
			q.Progress += num;
			SaveProgress(player, q.Tier);
			if (q.Complete)
			{
				return Claim(player, q, out message);
			}
			message = $"Entregue {num}. Faltam {q.Required - q.Progress}.";
			return true;
		}

		public static bool Claim(Player player, Quest q, out string message)
		{
			message = null;
			if (q.Claimed || !q.Accepted || !q.Complete)
			{
				message = "Missao ainda nao concluida.";
				return false;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Coins");
			ItemDrop val = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val == (Object)null)
			{
				message = "Moeda indisponivel.";
				return false;
			}
			int num = q.GoldReward;
			int num2 = Mathf.Max(1, val.m_itemData.m_shared.m_maxStackSize);
			while (num > 0)
			{
				int num3 = Mathf.Min(num2, num);
				if (inventory.AddItem(((Object)((Component)val).gameObject).name, num3, val.m_itemData.m_quality, val.m_itemData.m_variant, 0L, "", false) == null)
				{
					message = "Sem espaco na mochila para a recompensa.";
					return false;
				}
				num -= num3;
			}
			KillXpNetwork.Award(player, q.XpReward, null);
			q.Claimed = true;
			SaveProgress(player, q.Tier);
			message = $"Missao concluida! {q.GoldReward} moedas e {q.XpReward} XP";
			return true;
		}
	}
	[HarmonyPatch(typeof(Player), "Load")]
	internal static class Player_Load_QuestCachePatch
	{
		private static void Postfix()
		{
			QuestSystem.ClearCache();
		}
	}
	public class QuestTracker : MonoBehaviour
	{
		private const float W = 250f;

		private float _refresh;

		private List<Quest> _active = new List<Quest>();

		private void Update()
		{
			_refresh -= Time.unscaledDeltaTime;
			if (!(_refresh > 0f))
			{
				_refresh = 1f;
				Player localPlayer = Player.m_localPlayer;
				_active = (((Object)(object)localPlayer != (Object)null && ModConfig.QuestTrackerEnabled.Value) ? QuestSystem.Active(localPlayer) : new List<Quest>());
			}
		}

		private void OnGUI()
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.QuestTrackerEnabled.Value || _active.Count == 0 || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)Hud.instance == (Object)null || !Hud.instance.m_rootObject.activeSelf || Menu.IsVisible() || InventoryGui.IsVisible() || StoreGui.IsVisible() || Minimap.IsOpen() || Console.IsVisible())
			{
				return;
			}
			GUISkin skin = GUI.skin;
			Matrix4x4 matrix = GUI.matrix;
			GUI.skin = MmoUI.Skin;
			float num = Mathf.Clamp((float)Screen.height / 1080f, 0.75f, 2.5f);
			GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(num, num, 1f));
			float num2 = (float)Screen.width / num;
			string text = ColorUtility.ToHtmlStringRGB(MmoUI.MutedC);
			string text2 = ColorUtility.ToHtmlStringRGB(MmoUI.GoldC);
			GUILayout.BeginArea(new Rect(num2 - 250f - ModConfig.QuestTrackerOffsetX.Value, ModConfig.QuestTrackerOffsetY.Value, 250f, 0f));
			GUILayout.Label("<size=12><color=#" + text2 + "><b>MISSOES</b></color></size>", Array.Empty<GUILayoutOption>());
			foreach (Quest item in _active)
			{
				string text3 = CitySystem.ByTier(item.Tier)?.Name ?? BiomeTiers.Name(item.Tier);
				string text4 = (item.Complete ? ("<color=#" + text2 + ">completa</color>") : $"{item.Progress}/{item.Required}");
				GUILayout.Label("<size=12>" + item.ShortTitle + "  <color=#" + text2 + ">" + text4 + "</color></size>\n<size=10><color=#" + text + ">" + text3 + "</color></size>", Array.Empty<GUILayoutOption>());
			}
			GUILayout.EndArea();
			GUI.matrix = matrix;
			GUI.skin = skin;
		}
	}
}
namespace ValheimMMO.Pvp
{
	internal static class Karma
	{
		private const string Key = "mmo.karma";

		public const string ZdoKey = "mmo_karma";

		private const string RpcKill = "ValheimMMO_KarmaKill";

		private static float _syncTimer;

		private static float _lastSynced = -1f;

		public static float Of(Player p)
		{
			if ((Object)(object)p == (Object)null)
			{
				return 0f;
			}
			if ((Object)(object)p == (Object)(object)Player.m_localPlayer)
			{
				return Local(p);
			}
			ZDO obj = (((Object)(object)((Character)p).m_nview != (Object)null && ((Character)p).m_nview.IsValid()) ? ((Character)p).m_nview.GetZDO() : null);
			if (obj == null)
			{
				return 0f;
			}
			return obj.GetFloat("mmo_karma", 0f);
		}

		public static float Local(Player p)
		{
			if (p.m_customData.TryGetValue("mmo.karma", out var value) && float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return result;
			}
			return 0f;
		}

		public static bool IsWanted(Player p)
		{
			if (ModConfig.PvpEnabled.Value)
			{
				return Of(p) >= ModConfig.WantedThreshold.Value;
			}
			return false;
		}

		public static bool IsOutlaw(Player p)
		{
			if (ModConfig.PvpEnabled.Value)
			{
				return Of(p) >= ModConfig.OutlawThreshold.Value;
			}
			return false;
		}

		public static string StatusName(float k)
		{
			if (k >= ModConfig.OutlawThreshold.Value)
			{
				return "Fora da lei";
			}
			if (k >= ModConfig.WantedThreshold.Value)
			{
				return "Procurado";
			}
			return "Limpo";
		}

		public static void Set(Player p, float value, bool announce = true)
		{
			if ((Object)(object)p == (Object)null)
			{
				return;
			}
			float num = Local(p);
			value = Mathf.Clamp(value, 0f, ModConfig.KarmaMax.Value);
			p.m_customData["mmo.karma"] = value.ToString("R", CultureInfo.InvariantCulture);
			Sync(p, force: true);
			if (announce)
			{
				bool num2 = num >= ModConfig.WantedThreshold.Value;
				bool flag = value >= ModConfig.WantedThreshold.Value;
				if (!num2 && flag)
				{
					((Character)p).Message((MessageType)2, "Voce agora e PROCURADO. Guardas vao atacar e as cidades fecham para voce.", 0, (Sprite)null);
				}
				if (num2 && !flag)
				{
					((Character)p).Message((MessageType)2, "Seu nome foi limpo.", 0, (Sprite)null);
				}
			}
		}

		public static void Add(Player p, float delta, bool announce = true)
		{
			Set(p, Local(p) + delta, announce);
		}

		private static void Sync(Player p, bool force)
		{
			if (!((Object)(object)((Character)p).m_nview == (Object)null) && ((Character)p).m_nview.IsValid() && ((Character)p).m_nview.IsOwner())
			{
				float num = Local(p);
				if (force || !(Mathf.Abs(num - _lastSynced) < 0.05f))
				{
					((Character)p).m_nview.GetZDO().Set("mmo_karma", num);
					_lastSynced = num;
				}
			}
		}

		internal static void Tick(Player p, float dt)
		{
			if (!ModConfig.PvpEnabled.Value || (Object)(object)p == (Object)null)
			{
				return;
			}
			float num = Local(p);
			if (num > 0f)
			{
				float num2 = Mathf.Max(0f, num - ModConfig.KarmaDecayPerMinute.Value / 60f * dt);
				if (num2 != num)
				{
					bool num3 = num >= ModConfig.WantedThreshold.Value && num2 < ModConfig.WantedThreshold.Value;
					p.m_customData["mmo.karma"] = num2.ToString("R", CultureInfo.InvariantCulture);
					if (num3)
					{
						((Character)p).Message((MessageType)2, "Seu nome foi limpo.", 0, (Sprite)null);
					}
				}
			}
			_syncTimer += dt;
			if (_syncTimer >= 2f)
			{
				_syncTimer = 0f;
				Sync(p, force: false);
			}
		}

		internal static void OnMonsterKill(float victimMaxHp, bool boss)
		{
			Player localPlayer = Player.m_localPlayer;
			if (ModConfig.PvpEnabled.Value && !((Object)(object)localPlayer == (Object)null) && !(Local(localPlayer) <= 0f))
			{
				float num = ModConfig.KarmaMonsterFactor.Value * Mathf.Pow(Mathf.Max(1f, victimMaxHp), 0.6f) * (boss ? 5f : 1f);
				Add(localPlayer, 0f - num);
			}
		}

		internal static void Register()
		{
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.Register<string, float>("ValheimMMO_KarmaKill", (Action<long, string, float>)OnKillCredit);
			}
		}

		internal static void OnPlayerDied(Player victim)
		{
			if (!ModConfig.PvpEnabled.Value || (Object)(object)victim == (Object)null)
			{
				return;
			}
			float num = Local(victim);
			if (num > 0f)
			{
				Add(victim, 0f - ModConfig.KarmaDeathLoss.Value, announce: false);
			}
			HitData lastHit = ((Character)victim).m_lastHit;
			Character obj = ((lastHit != null) ? lastHit.GetAttacker() : null);
			Player val = (Player)(object)((obj is Player) ? obj : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)victim)
			{
				return;
			}
			ZDO val2 = (((Object)(object)((Character)val).m_nview != (Object)null && ((Character)val).m_nview.IsValid()) ? ((Character)val).m_nview.GetZDO() : null);
			if (val2 == null)
			{
				return;
			}
			long owner = val2.GetOwner();
			if ((Object)(object)val == (Object)(object)Player.m_localPlayer)
			{
				OnKillCredit(0L, victim.GetPlayerName(), num);
				return;
			}
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null)
			{
				instance.InvokeRoutedRPC(owner, "ValheimMMO_KarmaKill", new object[2]
				{
					victim.GetPlayerName(),
					num
				});
			}
		}

		private static void OnKillCredit(long sender, string victimName, float victimKarma)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !ModConfig.PvpEnabled.Value)
			{
				return;
			}
			if (victimKarma >= ModConfig.WantedThreshold.Value)
			{
				int num = Mathf.RoundToInt(victimKarma * ModConfig.BountyPerKarma.Value);
				if (num > 0)
				{
					KillXpNetwork.GiveGoldPublic(localPlayer, num, $"Recompensa por {victimName}: {num} moedas");
				}
			}
			else
			{
				Add(localPlayer, ModConfig.KarmaPerKill.Value);
				((Character)localPlayer).Message((MessageType)1, $"Assassinato de {victimName}: +{ModConfig.KarmaPerKill.Value:0} karma", 0, (Sprite)null);
			}
		}
	}
	[HarmonyPatch(typeof(Game), "Start")]
	internal static class Game_Start_KarmaPatch
	{
		private static void Postfix()
		{
			Karma.Register();
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })]
	internal static class Player_UpdateStats_KarmaPatch
	{
		private static void Postfix(Player __instance, float dt)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				Karma.Tick(__instance, dt);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "OnDeath")]
	internal static class Player_OnDeath_KarmaPatch
	{
		private static void Prefix(Player __instance)
		{
			if ((Object)(object)__instance != (Object)null && (Object)(object)((Character)__instance).m_nview != (Object)null && ((Character)__instance).m_nview.IsOwner())
			{
				Karma.OnPlayerDied(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "GetHoverName")]
	[HarmonyPriority(200)]
	internal static class Player_GetHoverName_KarmaPatch
	{
		private static void Postfix(Player __instance, ref string __result)
		{
			if (ModConfig.PvpEnabled.Value && Karma.IsWanted(__instance))
			{
				__result = "<color=#E04A3A>☠ " + __result + "</color>";
			}
		}
	}
	[HarmonyPatch(typeof(StoreGui), "Show")]
	internal static class StoreGui_Show_KarmaPatch
	{
		private static bool Prefix(Trader trader)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !Karma.IsWanted(localPlayer))
			{
				return true;
			}
			if (!MerchantSpawner.IsMerchant(trader))
			{
				return true;
			}
			((Character)localPlayer).Message((MessageType)2, "O mercador nao negocia com procurados.", 0, (Sprite)null);
			return false;
		}
	}
	[HarmonyPatch(typeof(TeleportWorld), "Teleport")]
	internal static class TeleportWorld_Teleport_KarmaPatch
	{
		private static bool Prefix(TeleportWorld __instance, Player player)
		{
			if ((Object)(object)player == (Object)null || !Karma.IsWanted(player))
			{
				return true;
			}
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			ZDO val = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO() : null);
			if (val == null || !val.GetBool("mmo_city_portal", false))
			{
				return true;
			}
			((Character)player).Message((MessageType)2, "O portal da cidade rejeita procurados.", 0, (Sprite)null);
			return false;
		}
	}
	[HarmonyPatch(typeof(EnemyHud), "TestShow")]
	internal static class EnemyHud_TestShow_StealthPatch
	{
		private static void Postfix(Character c, ref bool __result)
		{
			if (__result && ModConfig.StealthHidesName.Value)
			{
				Player val = (Player)(object)((c is Player) ? c : null);
				if (val != null && (Object)(object)val != (Object)(object)Player.m_localPlayer && ((Character)val).IsCrouching())
				{
					__result = false;
				}
			}
		}
	}
}
namespace ValheimMMO.Progression
{
	public enum Attr
	{
		Vitality,
		Endurance,
		Spirit,
		Conditioning
	}
	public static class AttrInfo
	{
		public const int Count = 4;

		public static readonly Attr[] All = new Attr[4]
		{
			Attr.Vitality,
			Attr.Endurance,
			Attr.Spirit,
			Attr.Conditioning
		};

		public static string DisplayName(Attr a)
		{
			return a switch
			{
				Attr.Vitality => "Vitalidade", 
				Attr.Endurance => "Resistencia", 
				Attr.Spirit => "Espirito", 
				Attr.Conditioning => "Condicionamento", 
				_ => a.ToString(), 
			};
		}

		public static string Short(Attr a)
		{
			return a switch
			{
				Attr.Vitality => "VIT", 
				Attr.Endurance => "RES", 
				Attr.Spirit => "ESP", 
				Attr.Conditioning => "CON", 
				_ => "?", 
			};
		}

		public static string Effect(Attr a)
		{
			return a switch
			{
				Attr.Vitality => "Vida maxima", 
				Attr.Endurance => "Stamina maxima", 
				Attr.Spirit => "Eitr maximo", 
				Attr.Conditioning => "Peso maximo", 
				_ => "", 
			};
		}
	}
	public static class ItemBonuses
	{
		public static bool Enabled => ModConfig.ItemBonusesEnabled.Value;

		public static int[] For(ItemData item)
		{
			if (item != null)
			{
				return For(item, item.m_quality, item.m_worldLevel);
			}
			return new int[4];
		}

		public static int[] For(ItemData item, int quality, float worldLevel)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected I4, but got Unknown
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Invalid comparison between Unknown and I4
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Invalid comparison between Unknown and I4
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Invalid comparison between Unknown and I4
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Invalid comparison between Unknown and I4
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Invalid comparison between Unknown and I4
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			int[] result = new int[4];
			if (!Enabled || item?.m_shared == null)
			{
				return result;
			}
			SharedData shared = item.m_shared;
			quality = Mathf.Max(1, quality);
			ItemType itemType = shared.m_itemType;
			switch (itemType - 3)
			{
			default:
				if ((int)itemType != 22)
				{
					break;
				}
				goto case 0;
			case 3:
			case 4:
			case 8:
			{
				float armor2 = item.GetArmor(quality, worldLevel);
				Add(result, ArmorAttribute(shared), armor2 * ModConfig.ArmorToAttribute.Value);
				break;
			}
			case 14:
			{
				float armor = item.GetArmor(quality, worldLevel);
				Add(result, Attr.Conditioning, armor * ModConfig.ArmorToAttribute.Value);
				break;
			}
			case 2:
			{
				float blockPower = item.GetBlockPower(quality, 0f);
				Add(result, Attr.Vitality, blockPower * ModConfig.BlockToAttribute.Value);
				break;
			}
			case 0:
			case 1:
			case 11:
			{
				SkillType skillType = shared.m_skillType;
				DamageTypes damage;
				if ((int)skillType == 9 || (int)skillType == 10)
				{
					float value = ModConfig.MagicStaffBase.Value + ModConfig.MagicStaffPerQuality.Value * (float)(quality - 1);
					Add(result, Attr.Spirit, value);
				}
				else if ((int)skillType == 8 || (int)skillType == 14)
				{
					damage = item.GetDamage(quality, worldLevel);
					float totalDamage = ((DamageTypes)(ref damage)).GetTotalDamage();
					Add(result, Attr.Endurance, totalDamage * ModConfig.RangedDamageToAttribute.Value);
				}
				else
				{
					damage = item.GetDamage(quality, worldLevel);
					float totalDamage2 = ((DamageTypes)(ref damage)).GetTotalDamage();
					Add(result, Attr.Endurance, totalDamage2 * ModConfig.MeleeDamageToAttribute.Value);
				}
				break;
			}
			case 5:
			case 6:
			case 7:
			case 9:
			case 10:
			case 12:
			case 13:
				break;
			}
			return result;
		}

		private static void Add(int[] result, Attr attr, float value)
		{
			int num = Mathf.RoundToInt(value);
			if (num > 0)
			{
				result[(int)attr] += num;
			}
		}

		public static Attr ArmorAttribute(SharedData shared)
		{
			if (shared.m_eitrRegenModifier > 0f)
			{
				return Attr.Spirit;
			}
			if (shared.m_movementModifier <= ModConfig.HeavyArmorMovementThreshold.Value)
			{
				return Attr.Vitality;
			}
			return Attr.Endurance;
		}

		public static int[] TotalEquipped(Humanoid humanoid)
		{
			int[] array = new int[4];
			if (!Enabled || (Object)(object)humanoid == (Object)null)
			{
				return array;
			}
			Inventory inventory = humanoid.GetInventory();
			if (inventory == null)
			{
				return array;
			}
			foreach (ItemData equippedItem in inventory.GetEquippedItems())
			{
				int[] array2 = For(equippedItem);
				for (int i = 0; i < array.Length; i++)
				{
					array[i] += array2[i];
				}
			}
			return array;
		}

		public static bool Any(int[] bonuses)
		{
			if (bonuses == null)
			{
				return false;
			}
			for (int i = 0; i < bonuses.Length; i++)
			{
				if (bonuses[i] != 0)
				{
					return true;
				}
			}
			return false;
		}

		public static string Describe(int[] bonuses, bool shortNames = true)
		{
			List<string> list = new List<string>();
			for (int i = 0; i < bonuses.Length; i++)
			{
				if (bonuses[i] != 0)
				{
					Attr a = (Attr)i;
					list.Add($"+{bonuses[i]} {(shortNames ? AttrInfo.Short(a) : AttrInfo.DisplayName(a))}");
				}
			}
			return string.Join(", ", list);
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
	{
		typeof(ItemData),
		typeof(int),
		typeof(bool),
		typeof(float),
		typeof(int)
	})]
	internal static class ItemData_GetTooltip_Patch
	{
		private static void Postfix(ItemData item, int qualityLevel, float worldLevel, ref string __result)
		{
			if (!ModConfig.ShowItemBonusTooltip.Value || !ItemBonuses.Enabled)
			{
				return;
			}
			int[] array = ItemBonuses.For(item, qualityLevel, worldLevel);
			if (!ItemBonuses.Any(array))
			{
				return;
			}
			StringBuilder stringBuilder = new StringBuilder(__result);
			stringBuilder.Append("\n");
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i] != 0)
				{
					Attr a = (Attr)i;
					stringBuilder.Append($"\n{AttrInfo.DisplayName(a)}: <color=orange>+{array[i]}</color>");
				}
			}
			__result = stringBuilder.ToString();
		}
	}
	[HarmonyPatch(typeof(Humanoid), "EquipItem")]
	internal static class Humanoid_EquipItem_Patch
	{
		private static void Postfix(Humanoid __instance, bool __result)
		{
			if (__result)
			{
				RefreshIfLocal(__instance);
			}
		}

		internal static void RefreshIfLocal(Humanoid humanoid)
		{
			Player val = (Player)(object)((humanoid is Player) ? humanoid : null);
			if (val != null && (Object)(object)val == (Object)(object)Player.m_localPlayer)
			{
				val.UpdateFood(0f, true);
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "UnequipItem")]
	internal static class Humanoid_UnequipItem_Patch
	{
		private static void Postfix(Humanoid __instance)
		{
			Humanoid_EquipItem_Patch.RefreshIfLocal(__instance);
		}
	}
	[HarmonyPatch(typeof(Player), "GetMaxCarryWeight")]
	internal static class Player_GetMaxCarryWeight_Patch
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			PlayerProgress playerProgress = PlayerProgress.Get(__instance);
			if (playerProgress != null)
			{
				__result += playerProgress.CarryBonusKg(__instance);
			}
		}
	}
	public static class LevelCurve
	{
		public static long XpToNext(int level)
		{
			if (level < 1)
			{
				level = 1;
			}
			if (level >= ModConfig.MaxLevel.Value)
			{
				return 0L;
			}
			return (long)Math.Round((double)ModConfig.XpCurveFactor.Value * Math.Pow(level, ModConfig.XpCurveExponent.Value));
		}

		public static long TotalXpForLevel(int level)
		{
			long num = 0L;
			for (int i = 1; i < level; i++)
			{
				num += XpToNext(i);
			}
			return num;
		}

		public static int PointsGrantedAt(int level)
		{
			return Math.Max(0, (level - 1) * ModConfig.PointsPerLevel.Value);
		}

		public static long XpForKill(Character victim)
		{
			if ((Object)(object)victim == (Object)null)
			{
				return 0L;
			}
			float num = 0f;
			try
			{
				num = victim.GetMaxHealth();
			}
			catch
			{
			}
			if (num <= 0f)
			{
				num = victim.GetMaxHealthBase();
			}
			if (num <= 0f)
			{
				return 0L;
			}
			int num2 = Math.Max(0, victim.GetLevel() - 1);
			double num3 = 1.0 + (double)(ModConfig.XpStarBonus.Value * (float)num2);
			double num4 = 1.0;
			if (victim.IsBoss())
			{
				num4 = (DungeonBosses.IsDungeonBoss(victim, out var _) ? ModConfig.XpDungeonBossMultiplier.Value : ModConfig.XpBossMultiplier.Value);
			}
			return (long)Math.Ceiling((double)ModConfig.XpKillFactor.Value * Math.Pow(num, ModConfig.XpKillExponent.Value) * num3 * num4);
		}
	}
	internal static class LevelDisplay
	{
		public const string ZdoKey = "mmo_level";

		public static void Sync(Player player, int level)
		{
			if (!((Object)(object)player == (Object)null) && !((Object)(object)((Character)player).m_nview == (Object)null) && ((Character)player).m_nview.IsValid() && ((Character)player).m_nview.IsOwner())
			{
				ZDO zDO = ((Character)player).m_nview.GetZDO();
				if (zDO.GetInt("mmo_level", -1) != level)
				{
					zDO.Set("mmo_level", level);
				}
			}
		}

		public static int LevelOf(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return 0;
			}
			if ((Object)(object)player == (Object)(object)Player.m_localPlayer)
			{
				return PlayerProgress.Get(player)?.Level ?? 0;
			}
			ZDO obj = (((Object)(object)((Character)player).m_nview != (Object)null && ((Character)player).m_nview.IsValid()) ? ((Character)player).m_nview.GetZDO() : null);
			if (obj == null)
			{
				return 0;
			}
			return obj.GetInt("mmo_level", 0);
		}
	}
	[HarmonyPatch(typeof(Player), "GetHoverName")]
	internal static class Player_GetHoverName_LevelPatch
	{
		private static void Postfix(Player __instance, ref string __result)
		{
			if (ModConfig.ShowPlayerLevels.Value)
			{
				int num = LevelDisplay.LevelOf(__instance);
				if (num > 0)
				{
					__result = $"{__result} <color=#F2C766>Lv {num}</color>";
				}
			}
		}
	}
	public class PlayerProgress
	{
		private const string CustomDataKey = "mmo.progression";

		private const int Format = 2;

		public int Level = 1;

		public long Xp;

		public readonly int[] Spent = new int[4];

		public float Satiety = -1f;

		private static readonly ConditionalWeakTable<Player, PlayerProgress> Cache = new ConditionalWeakTable<Player, PlayerProgress>();

		public static PlayerProgress Local
		{
			get
			{
				if (!((Object)(object)Player.m_localPlayer != (Object)null))
				{
					return null;
				}
				return Get(Player.m_localPlayer);
			}
		}

		public int TotalPoints => LevelCurve.PointsGrantedAt(Level);

		public int SpentPoints
		{
			get
			{
				int num = 0;
				for (int i = 0; i < Spent.Length; i++)
				{
					num += Spent[i];
				}
				return num;
			}
		}

		public int UnspentPoints => Math.Max(0, TotalPoints - SpentPoints);

		public long XpForNextLevel => LevelCurve.XpToNext(Level);

		public float LevelProgress
		{
			get
			{
				long xpForNextLevel = XpForNextLevel;
				if (xpForNextLevel > 0)
				{
					return Math.Min(1f, (float)Xp / (float)xpForNextLevel);
				}
				return 1f;
			}
		}

		public static PlayerProgress Get(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			if (Cache.TryGetValue(player, out var value))
			{
				return value;
			}
			PlayerProgress playerProgress = new PlayerProgress();
			playerProgress.LoadFrom(player);
			Cache.Add(player, playerProgress);
			return playerProgress;
		}

		public static void ClearCache(Player player)
		{
			if ((Object)(object)player != (Object)null)
			{
				Cache.Remove(player);
			}
		}

		public bool TrySpend(Attr attr, Player owner)
		{
			if (UnspentPoints <= 0)
			{
				return false;
			}
			Spent[(int)attr]++;
			SaveTo(owner);
			return true;
		}

		public bool TryRefund(Attr attr, Player owner, out string reason)
		{
			reason = null;
			if (!ModConfig.RespecEnabled.Value)
			{
				reason = "Respec esta desativado neste servidor.";
				return false;
			}
			if (Spent[(int)attr] <= 0)
			{
				reason = "Nenhum ponto investido nesse atributo.";
				return false;
			}
			if (!CanRespec(owner, out reason))
			{
				return false;
			}
			Spent[(int)attr]--;
			SaveTo(owner);
			return true;
		}

		public bool RespecAll(Player owner, out string reason)
		{
			reason = null;
			if (!ModConfig.RespecEnabled.Value)
			{
				reason = "Respec esta desativado neste servidor.";
				return false;
			}
			if (SpentPoints == 0)
			{
				reason = "Nao ha pontos para redistribuir.";
				return false;
			}
			if (!CanRespec(owner, out reason))
			{
				return false;
			}
			Array.Clear(Spent, 0, Spent.Length);
			SaveTo(owner);
			return true;
		}

		public static bool CanRespec(Player player, out string reason)
		{
			reason = null;
			if ((Object)(object)player == (Object)null)
			{
				reason = "Jogador invalido.";
				return false;
			}
			if (ModConfig.RespecRequiresShelter.Value && !player.InShelter())
			{
				reason = "Voce precisa estar sob abrigo para redistribuir pontos.";
				return false;
			}
			int value = ModConfig.RespecMinComfort.Value;
			if (value > 0 && player.GetComfortLevel() < value)
			{
				reason = $"Conforto insuficiente ({player.GetComfortLevel()}/{value}). " + "Aproxime-se de uma fogueira e de moveis.";
				return false;
			}
			return true;
		}

		public int AddXp(long amount, Player owner)
		{
			if (amount <= 0)
			{
				return 0;
			}
			int value = ModConfig.MaxLevel.Value;
			if (Level >= value)
			{
				return 0;
			}
			Xp += amount;
			int num = 0;
			while (Level < value)
			{
				long num2 = LevelCurve.XpToNext(Level);
				if (num2 <= 0 || Xp < num2)
				{
					break;
				}
				Xp -= num2;
				Level++;
				num++;
			}
			if (Level >= value)
			{
				Xp = 0L;
			}
			SaveTo(owner);
			return num;
		}

		public int ApplyDeathPenalty(Player owner)
		{
			float num = ModConfig.DeathXpLossPercent.Value / 100f;
			if (num <= 0f)
			{
				return 0;
			}
			long num2 = (long)Math.Round((float)LevelCurve.XpToNext(Level) * num);
			if (num2 <= 0)
			{
				return 0;
			}
			Xp -= num2;
			int num3 = 0;
			if (ModConfig.DeathCanDelevel.Value)
			{
				while (Xp < 0 && Level > 1)
				{
					Level--;
					num3++;
					Xp += LevelCurve.XpToNext(Level);
				}
			}
			if (Xp < 0)
			{
				Xp = 0L;
			}
			if (num3 > 0)
			{
				ReclaimExcessPoints();
			}
			SaveTo(owner);
			return num3;
		}

		private void ReclaimExcessPoints()
		{
			int num = SpentPoints - TotalPoints;
			while (num > 0)
			{
				int num2 = 0;
				for (int i = 1; i < Spent.Length; i++)
				{
					if (Spent[i] > Spent[num2])
					{
						num2 = i;
					}
				}
				if (Spent[num2] > 0)
				{
					Spent[num2]--;
					num--;
					continue;
				}
				break;
			}
		}

		public int EffectivePoints(Attr attr, Player player)
		{
			int num = ItemBonuses.TotalEquipped((Humanoid)(object)player)[(int)attr];
			return Spent[(int)attr] + num;
		}

		public void ComputeStats(Player player, out float hp, out float stamina, out float eitr)
		{
			int num = Math.Max(0, Level - 1);
			float num2 = (((Object)(object)player != (Object)null) ? player.m_baseHP : 25f);
			float num3 = (((Object)(object)player != (Object)null) ? player.m_baseStamina : 50f);
			int[] array = ItemBonuses.TotalEquipped((Humanoid)(object)player);
			hp = num2 + (float)num * ModConfig.GrowthHealthPerLevel.Value + (float)(Spent[0] + array[0]) * ModConfig.HealthPerVitality.Value;
			stamina = num3 + (float)num * ModConfig.GrowthStaminaPerLevel.Value + (float)(Spent[1] + array[1]) * ModConfig.StaminaPerEndurance.Value;
			eitr = (float)num * ModConfig.GrowthEitrPerLevel.Value + (float)(Spent[2] + array[2]) * ModConfig.EitrPerSpirit.Value;
			if (hp < 1f)
			{
				hp = 1f;
			}
			if (stamina < 1f)
			{
				stamina = 1f;
			}
			if (eitr < 0f)
			{
				eitr = 0f;
			}
		}

		public float CarryBonusKg(Player player)
		{
			int num = Math.Max(0, Level - 1);
			int num2 = Spent[3] + ItemBonuses.TotalEquipped((Humanoid)(object)player)[3];
			return (float)num * ModConfig.GrowthCarryPerLevel.Value + (float)num2 * ModConfig.CarryPerConditioning.Value;
		}

		public void SaveTo(Player player)
		{
			if (!((Object)(object)player == (Object)null))
			{
				CultureInfo invariantCulture = CultureInfo.InvariantCulture;
				List<string> list = new List<string>
				{
					2.ToString(invariantCulture),
					Level.ToString(invariantCulture),
					Xp.ToString(invariantCulture)
				};
				for (int i = 0; i < 4; i++)
				{
					list.Add(Spent[i].ToString(invariantCulture));
				}
				list.Add(Satiety.ToString("R", invariantCulture));
				player.m_customData["mmo.progression"] = string.Join("|", list);
				LevelDisplay.Sync(player, Level);
			}
		}

		public void LoadFrom(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			if (!player.m_customData.TryGetValue("mmo.progression", out var value) || string.IsNullOrEmpty(value))
			{
				Reset();
				return;
			}
			try
			{
				CultureInfo invariantCulture = CultureInfo.InvariantCulture;
				string[] array = value.Split('|');
				int num = int.Parse(array[0], invariantCulture);
				Level = Math.Max(1, int.Parse(array[1], invariantCulture));
				Xp = Math.Max(0L, long.Parse(array[2], invariantCulture));
				int num2 = ((num >= 2) ? 4 : 3);
				Array.Clear(Spent, 0, Spent.Length);
				for (int i = 0; i < num2 && i < 4; i++)
				{
					Spent[i] = Math.Max(0, int.Parse(array[3 + i], invariantCulture));
				}
				int num3 = 3 + num2;
				Satiety = ((array.Length > num3) ? float.Parse(array[num3], NumberStyles.Float, invariantCulture) : (-1f));
				Clamp();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Nao foi possivel ler a progressao de " + player.GetPlayerName() + ", resetando. Dado bruto: '" + value + "'. Erro: " + ex.Message));
				Reset();
			}
		}

		private void Clamp()
		{
			if (Level > ModConfig.MaxLevel.Value)
			{
				Level = ModConfig.MaxLevel.Value;
			}
			if (SpentPoints > TotalPoints)
			{
				ReclaimExcessPoints();
			}
		}

		public void Reset()
		{
			Level = 1;
			Xp = 0L;
			Array.Clear(Spent, 0, Spent.Length);
			Satiety = -1f;
		}

		public override string ToString()
		{
			return $"lvl {Level} ({Xp}/{XpForNextLevel} xp) " + $"VIT {Spent[0]} RES {Spent[1]} ESP {Spent[2]} CON {Spent[3]} " + $"livres {UnspentPoints}";
		}
	}
	[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
	internal static class Player_GetTotalFoodValue_Patch
	{
		private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr)
		{
			PlayerProgress playerProgress = PlayerProgress.Get(__instance);
			if (playerProgress != null)
			{
				playerProgress.ComputeStats(__instance, out var hp2, out var stamina2, out var eitr2);
				if (ModConfig.FoodGivesNoStats.Value)
				{
					hp = hp2;
					stamina = stamina2;
					eitr = eitr2;
				}
				else
				{
					hp += hp2 - __instance.m_baseHP;
					stamina += stamina2 - __instance.m_baseStamina;
					eitr += eitr2;
				}
			}
		}
	}
	internal static class KillXpNetwork
	{
		private const string RpcName = "ValheimMMO_KillXp";

		private static readonly ConditionalWeakTable<Character, HashSet<ZDOID>> Contributors = new ConditionalWeakTable<Character, HashSet<ZDOID>>();

		internal static void Register()
		{
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.Register<ZPackage>("ValheimMMO_KillXp", (Action<long, ZPackage>)OnKillXp);
				Plugin.Log.LogInfo((object)"RPC de XP registrado.");
			}
		}

		internal static void RecordHit(Character victim, HitData hit)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)victim == (Object)null) && hit != null && !victim.IsPlayer() && !((ZDOID)(ref hit.m_attacker)).IsNone() && hit.GetAttacker() is Player && !(hit.GetTotalDamage() <= 0f))
			{
				Contributors.GetOrCreateValue(victim).Add(hit.m_attacker);
			}
		}

		internal static void BroadcastKill(Character victim)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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)
			if ((Object)(object)victim == (Object)null || ZRoutedRpc.instance == null)
			{
				return;
			}
			HashSet<ZDOID> value;
			bool flag = Contributors.TryGetValue(victim, out value) && value.Count > 0;
			bool flag2 = !ModConfig.XpRequiresOwnDamage.Value;
			if (!flag && !flag2)
			{
				Contributors.Remove(victim);
				return;
			}
			long num = LevelCurve.XpForKill(victim);
			num = (long)((float)num * ModConfig.XpGlobalRate.Value);
			if (num <= 0)
			{
				Contributors.Remove(victim);
				return;
			}
			ZPackage val = new ZPackage();
			val.Write(num);
			val.Write(victim.m_name ?? "");
			val.Write(((Component)victim).transform.position);
			val.Write(flag2);
			val.Write(flag ? value.Count : 0);
			if (flag)
			{
				foreach (ZDOID item in value)
				{
					val.Write(item);
				}
			}
			val.Write(((Object)((Component)victim).gameObject).name.Replace("(Clone)", ""));
			val.Write(DungeonBosses.IsDungeonBoss(victim, out var tier) ? tier.Id : 0);
			val.Write(WorldBoss.IsWorldBoss(victim, out var def) ? WorldBoss.GoldFor(def) : 0);
			ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "ValheimMMO_KillXp", new object[1] { val });
			Contributors.Remove(victim);
		}

		private static void OnKillXp(long sender, ZPackage pkg)
		{
			//IL_0022: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: 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)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || pkg == null)
			{
				return;
			}
			long num = pkg.ReadLong();
			string victimName = pkg.ReadString();
			Vector3 val = pkg.ReadVector3();
			bool flag = pkg.ReadBool();
			int num2 = pkg.ReadInt();
			ZDOID zDOID = ((Character)localPlayer).GetZDOID();
			bool flag2 = false;
			for (int i = 0; i < num2; i++)
			{
				if (pkg.ReadZDOID() == zDOID)
				{
					flag2 = true;
				}
			}
			string victimPrefab = pkg.ReadString();
			int num3 = pkg.ReadInt();
			int num4 = pkg.ReadInt();
			if (!flag2 && flag)
			{
				float num5 = Mathf.Max(1f, ModConfig.XpNearbyRadius.Value);
				flag2 = Vector3.Distance(((Component)localPlayer).transform.position, val) <= num5;
			}
			if (flag2)
			{
				Award(localPlayer, num, victimName);
				QuestSystem.OnKill(victimPrefab, num3);
				if (num4 > 0)
				{
					GiveGold(localPlayer, num4);
				}
				Karma.OnMonsterKill(Mathf.Pow(Mathf.Max(1f, (float)num / Mathf.Max(0.1f, ModConfig.XpKillFactor.Value * ModConfig.XpGlobalRate.Value)), 1.3333334f), num3 > 0 || num4 > 0);
			}
		}

		public static void GiveGoldPublic(Player player, int amount, string message)
		{
			GiveGold(player, amount, message);
		}

		private static void GiveGold(Player player, int amount, string message = null)
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			ObjectDB instance = ObjectDB.instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				GameObject itemPrefab = instance.GetItemPrefab("Coins");
				obj = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			}
			ItemDrop val = (ItemDrop)obj;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Inventory inventory = ((Humanoid)player).GetInventory();
			int num = Mathf.Max(1, val.m_itemData.m_shared.m_maxStackSize);
			int num2 = amount;
			while (num2 > 0)
			{
				int num3 = Mathf.Min(num, num2);
				if (inventory.AddItem(((Object)((Component)val).gameObject).name, num3, val.m_itemData.m_quality, val.m_itemData.m_variant, 0L, "", false) == null)
				{
					CharacterDrop.DropItems(new List<KeyValuePair<GameObject, int>>
					{
						new KeyValuePair<GameObject, int>(((Component)val).gameObject, 1)
					}, ((Component)player).transform.position + Vector3.up, 0.3f);
					break;
				}
				num2 -= num3;
			}
			((Character)player).Message((MessageType)2, message ?? $"Recompensa do chefe mundial: {amount} moedas", 0, (Sprite)null);
		}

		internal static void Award(Player player, long xp, string victimName)
		{
			PlayerProgress playerProgress = PlayerProgress.Get(player);
			if (playerProgress != null && xp > 0)
			{
				int level = playerProgress.Level;
				int num = playerProgress.AddXp(xp, player);
				string arg = (string.IsNullOrEmpty(victimName) ? "" : ("  (" + Localization.instance.Localize(victimName) + ")"));
				if (num > 0)
				{
					((Character)player).Message((MessageType)2, $"Level {playerProgress.Level}!  +{num * ModConfig.PointsPerLevel.Value} pontos", 0, (Sprite)null);
					Plugin.Log.LogInfo((object)$"Level up: {level} -> {playerProgress.Level} ({playerProgress})");
				}
				else if (ModConfig.ShowXpGainMessages.Value)
				{
					((Character)playe