Decompiled source of OttoAura v1.5.3

OttoAura.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using OttoAura.AuraBoost;
using OttoAura.AuraDispel;
using OttoAura.AuraMove;
using OttoAura.AuraTrade;
using OttoAura.Config;
using ServerSync;
using SkillManager;
using TMPro;
using UnityEngine;
using UnityEngine.PostProcessing;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("OttoAura")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("potto007")]
[assembly: AssemblyProduct("OttoAura")]
[assembly: AssemblyCopyright("Copyright © 2022-2026 OttoAura contributors")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("E0E2F92E-557C-4A05-9D89-AA92A0BD75C4")]
[assembly: AssemblyFileVersion("1.5.3")]
[assembly: InternalsVisibleTo("OttoAura.Tests")]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_postprocessing")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.5.3.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SkillManager
{
	[PublicAPI]
	public class Skill
	{
		public static class LocalizationCache
		{
			private static readonly Dictionary<string, Localization> localizations = new Dictionary<string, Localization>();

			internal static void LocalizationPostfix(Localization __instance, string language)
			{
				string key = localizations.FirstOrDefault<KeyValuePair<string, Localization>>((KeyValuePair<string, Localization> l) => l.Value == __instance).Key;
				if (key != null)
				{
					localizations.Remove(key);
				}
				if (!localizations.ContainsKey(language))
				{
					localizations.Add(language, __instance);
				}
			}

			public static Localization ForLanguage(string? language = null)
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Expected O, but got Unknown
				if (localizations.TryGetValue(language ?? PlayerPrefs.GetString("language", "English"), out Localization value))
				{
					return value;
				}
				value = new Localization();
				if (language != null)
				{
					value.SetupLanguage(language);
				}
				return value;
			}
		}

		[PublicAPI]
		public class LocalizeKey
		{
			private static readonly List<LocalizeKey> keys = new List<LocalizeKey>();

			public readonly string Key;

			public readonly Dictionary<string, string> Localizations = new Dictionary<string, string>();

			public LocalizeKey(string key)
			{
				Key = key.Replace("$", "");
			}

			public void Alias(string alias)
			{
				Localizations.Clear();
				if (!alias.Contains("$"))
				{
					alias = "$" + alias;
				}
				Localizations["alias"] = alias;
				Localization.instance.AddWord(Key, Localization.instance.Localize(alias));
			}

			public LocalizeKey English(string key)
			{
				return addForLang("English", key);
			}

			public LocalizeKey Swedish(string key)
			{
				return addForLang("Swedish", key);
			}

			public LocalizeKey French(string key)
			{
				return addForLang("French", key);
			}

			public LocalizeKey Italian(string key)
			{
				return addForLang("Italian", key);
			}

			public LocalizeKey German(string key)
			{
				return addForLang("German", key);
			}

			public LocalizeKey Spanish(string key)
			{
				return addForLang("Spanish", key);
			}

			public LocalizeKey Russian(string key)
			{
				return addForLang("Russian", key);
			}

			public LocalizeKey Romanian(string key)
			{
				return addForLang("Romanian", key);
			}

			public LocalizeKey Bulgarian(string key)
			{
				return addForLang("Bulgarian", key);
			}

			public LocalizeKey Macedonian(string key)
			{
				return addForLang("Macedonian", key);
			}

			public LocalizeKey Finnish(string key)
			{
				return addForLang("Finnish", key);
			}

			public LocalizeKey Danish(string key)
			{
				return addForLang("Danish", key);
			}

			public LocalizeKey Norwegian(string key)
			{
				return addForLang("Norwegian", key);
			}

			public LocalizeKey Icelandic(string key)
			{
				return addForLang("Icelandic", key);
			}

			public LocalizeKey Turkish(string key)
			{
				return addForLang("Turkish", key);
			}

			public LocalizeKey Lithuanian(string key)
			{
				return addForLang("Lithuanian", key);
			}

			public LocalizeKey Czech(string key)
			{
				return addForLang("Czech", key);
			}

			public LocalizeKey Hungarian(string key)
			{
				return addForLang("Hungarian", key);
			}

			public LocalizeKey Slovak(string key)
			{
				return addForLang("Slovak", key);
			}

			public LocalizeKey Polish(string key)
			{
				return addForLang("Polish", key);
			}

			public LocalizeKey Dutch(string key)
			{
				return addForLang("Dutch", key);
			}

			public LocalizeKey Portuguese_European(string key)
			{
				return addForLang("Portuguese_European", key);
			}

			public LocalizeKey Portuguese_Brazilian(string key)
			{
				return addForLang("Portuguese_Brazilian", key);
			}

			public LocalizeKey Chinese(string key)
			{
				return addForLang("Chinese", key);
			}

			public LocalizeKey Japanese(string key)
			{
				return addForLang("Japanese", key);
			}

			public LocalizeKey Korean(string key)
			{
				return addForLang("Korean", key);
			}

			public LocalizeKey Hindi(string key)
			{
				return addForLang("Hindi", key);
			}

			public LocalizeKey Thai(string key)
			{
				return addForLang("Thai", key);
			}

			public LocalizeKey Abenaki(string key)
			{
				return addForLang("Abenaki", key);
			}

			public LocalizeKey Croatian(string key)
			{
				return addForLang("Croatian", key);
			}

			public LocalizeKey Georgian(string key)
			{
				return addForLang("Georgian", key);
			}

			public LocalizeKey Greek(string key)
			{
				return addForLang("Greek", key);
			}

			public LocalizeKey Serbian(string key)
			{
				return addForLang("Serbian", key);
			}

			public LocalizeKey Ukrainian(string key)
			{
				return addForLang("Ukrainian", key);
			}

			private LocalizeKey addForLang(string lang, string value)
			{
				Localizations[lang] = value;
				if (Localization.instance.GetSelectedLanguage() == lang)
				{
					Localization.instance.AddWord(Key, value);
				}
				else if (lang == "English" && !Localization.instance.m_translations.ContainsKey(Key))
				{
					Localization.instance.AddWord(Key, value);
				}
				return this;
			}

			[HarmonyPriority(300)]
			internal static void AddLocalizedKeys(Localization __instance, string language)
			{
				foreach (LocalizeKey key in keys)
				{
					string value2;
					if (key.Localizations.TryGetValue(language, out string value) || key.Localizations.TryGetValue("English", out value))
					{
						__instance.AddWord(key.Key, value);
					}
					else if (key.Localizations.TryGetValue("alias", out value2))
					{
						Localization.instance.AddWord(key.Key, Localization.instance.Localize(value2));
					}
				}
			}
		}

		private class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public string? Category;
		}

		[HarmonyPatch(typeof(Skills), "IsSkillValid")]
		private static class Patch_Skills_IsSkillValid
		{
			private static void Postfix(SkillType type, ref bool __result)
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				if (!__result && skills.ContainsKey(type))
				{
					__result = true;
				}
			}
		}

		private static readonly Dictionary<SkillType, Skill> skills;

		internal static readonly Dictionary<string, Skill> skillByName;

		private readonly string skillName;

		private readonly string internalSkillName;

		private readonly SkillDef skillDef;

		public readonly LocalizeKey Name;

		public readonly LocalizeKey Description;

		private float skillEffectFactor = 1f;

		private int skillLoss = 5;

		public bool Configurable;

		private static bool InitializedTerminal;

		private static readonly MethodInfo? LoadImageMethod;

		private static Localization? _english;

		private static BaseUnityPlugin? _plugin;

		private static bool hasConfigSync;

		private static object? _configSync;

		public float SkillGainFactor
		{
			get
			{
				return skillDef.m_increseStep;
			}
			set
			{
				skillDef.m_increseStep = value;
				this.SkillGainFactorChanged?.Invoke(value);
			}
		}

		public float SkillEffectFactor
		{
			get
			{
				return skillEffectFactor;
			}
			set
			{
				skillEffectFactor = value;
				this.SkillEffectFactorChanged?.Invoke(value);
			}
		}

		public int SkillLoss
		{
			get
			{
				return skillLoss;
			}
			set
			{
				skillLoss = value;
				this.SkillLossChanged?.Invoke(value);
			}
		}

		private static Localization english => _english ?? (_english = LocalizationCache.ForLanguage("English"));

		private static BaseUnityPlugin plugin
		{
			get
			{
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_0046: Unknown result type (might be due to invalid IL or missing references)
				//IL_004c: Expected O, but got Unknown
				object obj = _plugin;
				if (obj == null)
				{
					BaseUnityPlugin val = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)Assembly.GetExecutingAssembly().DefinedTypes.First((TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t)));
					_plugin = val;
					obj = (object)val;
				}
				return (BaseUnityPlugin)obj;
			}
		}

		private static object? configSync
		{
			get
			{
				if (_configSync == null && hasConfigSync)
				{
					Type type = Assembly.GetExecutingAssembly().GetType("ServerSync.ConfigSync");
					if ((object)type != null)
					{
						_configSync = Activator.CreateInstance(type, plugin.Info.Metadata.GUID + " SkillManager");
						type.GetField("CurrentVersion").SetValue(_configSync, plugin.Info.Metadata.Version.ToString());
						type.GetProperty("IsLocked").SetValue(_configSync, true);
					}
					else
					{
						hasConfigSync = false;
					}
				}
				return _configSync;
			}
		}

		public event Action<float>? SkillGainFactorChanged;

		public event Action<float>? SkillEffectFactorChanged;

		public event Action<float>? SkillLossChanged;

		public Skill(string englishName, string icon)
			: this(englishName, loadSprite(icon, 64, 64))
		{
		}

		public unsafe Skill(string englishName, Sprite icon)
		{
			//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_003a: 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)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: 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_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			SkillType val = fromName(englishName);
			string text = new Regex("[^a-zA-Z]").Replace(englishName, "_");
			skills[val] = this;
			skillByName[englishName] = this;
			skillDef = new SkillDef
			{
				m_description = "$skilldesc_" + text,
				m_icon = icon,
				m_increseStep = 1f,
				m_skill = val
			};
			internalSkillName = text;
			skillName = englishName;
			Name = new LocalizeKey("skill_" + ((object)(*(SkillType*)(&val))/*cast due to .constrained prefix*/).ToString()).English(englishName);
			Description = new LocalizeKey("skilldesc_" + text);
		}

		public static SkillType fromName(string englishName)
		{
			return (SkillType)Math.Abs(StringExtensionMethods.GetStableHashCode(englishName));
		}

		static Skill()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Expected O, but got Unknown
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Expected O, but got Unknown
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Expected O, but got Unknown
			//IL_01db: Expected O, but got Unknown
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Expected O, but got Unknown
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Expected O, but got Unknown
			//IL_026c: Expected O, but got Unknown
			skills = new Dictionary<SkillType, Skill>();
			skillByName = new Dictionary<string, Skill>();
			InitializedTerminal = false;
			LoadImageMethod = AccessTools.Method("UnityEngine.ImageConversion:LoadImage", new Type[2]
			{
				typeof(Texture2D),
				typeof(byte[])
			}, (Type[])null);
			hasConfigSync = true;
			Harmony val = new Harmony("org.bepinex.helpers.skillmanager");
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_FejdStartup", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "GetSkillDef", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_GetSkillDef", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "CheatRaiseSkill", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_CheatRaiseskill", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "CheatResetSkill", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_CheatResetSkill", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "LoadCSV", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(LocalizeKey), "AddLocalizedKeys", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Terminal), "InitTerminal", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Terminal_InitTerminal_Prefix", (Type[])null, (Type[])null)), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Terminal_InitTerminal", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "SetupLanguage", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(LocalizationCache), "LocalizationPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "OnDeath", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_OnDeath_Prefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_OnDeath_Finalizer", (Type[])null, (Type[])null)), (HarmonyMethod)null);
		}

		private static void Patch_FejdStartup()
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Expected O, but got Unknown
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Expected O, but got Unknown
			foreach (Skill skill in skills.Values)
			{
				if (skill.Configurable)
				{
					string key = skill.Name.Key;
					string text = new Regex("['[\"\\]]").Replace(english.Localize(key), "").Trim();
					string category = Localization.instance.Localize(key).Trim();
					ConfigEntry<float> skillGain = config(text, "Skill gain factor", skill.SkillGainFactor, new ConfigDescription("The rate at which you gain experience for the skill.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 5f), new object[1]
					{
						new ConfigurationManagerAttributes
						{
							Category = category
						}
					}));
					skill.SkillGainFactor = skillGain.Value;
					skillGain.SettingChanged += delegate
					{
						skill.SkillGainFactor = skillGain.Value;
					};
					ConfigEntry<float> skillEffect = config(text, "Skill effect factor", skill.SkillEffectFactor, new ConfigDescription("The power of the skill, based on the default power.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 5f), new object[1]
					{
						new ConfigurationManagerAttributes
						{
							Category = category
						}
					}));
					skill.SkillEffectFactor = skillEffect.Value;
					skillEffect.SettingChanged += delegate
					{
						skill.SkillEffectFactor = skillEffect.Value;
					};
					ConfigEntry<int> skillLoss = config(text, "Skill loss", skill.skillLoss, new ConfigDescription("How much experience to lose on death.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), new object[1]
					{
						new ConfigurationManagerAttributes
						{
							Category = category
						}
					}));
					skill.skillLoss = skillLoss.Value;
					skillLoss.SettingChanged += delegate
					{
						skill.skillLoss = skillLoss.Value;
					};
				}
			}
		}

		private static void Patch_Skills_GetSkillDef(ref SkillDef? __result, List<SkillDef> ___m_skills, SkillType type)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			if (__result == null)
			{
				SkillDef val = GetSkillDef(type);
				if (val != null)
				{
					___m_skills.Add(val);
					__result = val;
				}
			}
		}

		private unsafe static bool Patch_Skills_CheatRaiseskill(Skills __instance, string name, float value, Player ___m_player)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			foreach (SkillType key in skills.Keys)
			{
				Skill skill = skills[key];
				if (string.Equals(skill.internalSkillName, name, StringComparison.CurrentCultureIgnoreCase))
				{
					Skill skill2 = __instance.GetSkill(key);
					skill2.m_level += value;
					skill2.m_level = Mathf.Clamp(skill2.m_level, 0f, 100f);
					((Character)___m_player).Message((MessageType)1, "Skill increased " + Localization.instance.Localize("$skill_" + ((object)(*(SkillType*)(&key))/*cast due to .constrained prefix*/).ToString()) + ": " + (int)skill2.m_level, 0, skill2.m_info.m_icon, false);
					Console.instance.Print("Skill " + skill.internalSkillName + " = " + skill2.m_level);
					return false;
				}
			}
			return true;
		}

		private static bool Patch_Skills_CheatResetSkill(Skills __instance, string name)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			foreach (SkillType key in skills.Keys)
			{
				Skill skill = skills[key];
				if (string.Equals(skill.internalSkillName, name, StringComparison.CurrentCultureIgnoreCase))
				{
					__instance.ResetSkill(key);
					Console.instance.Print("Skill " + skill.internalSkillName + " reset");
					return false;
				}
			}
			return true;
		}

		private static void Patch_Skills_OnDeath_Prefix(Skills __instance, ref Dictionary<SkillType, Skill>? __state)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if (__state == null)
			{
				__state = new Dictionary<SkillType, Skill>();
			}
			foreach (KeyValuePair<SkillType, Skill> skill in skills)
			{
				if (__instance.m_skillData.TryGetValue(skill.Key, out var value))
				{
					__state[skill.Key] = value;
					if (skill.Value.skillLoss > 0)
					{
						Skill obj = value;
						obj.m_level -= value.m_level * (float)skill.Value.SkillLoss / 100f;
						value.m_accumulator = 0f;
					}
					__instance.m_skillData.Remove(skill.Key);
				}
			}
		}

		private static void Patch_Skills_OnDeath_Finalizer(Skills __instance, ref Dictionary<SkillType, Skill>? __state)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (__state == null)
			{
				return;
			}
			foreach (KeyValuePair<SkillType, Skill> item in __state)
			{
				__instance.m_skillData[item.Key] = item.Value;
			}
			__state = null;
		}

		private static void Patch_Terminal_InitTerminal_Prefix()
		{
			InitializedTerminal = Terminal.m_terminalInitialized;
		}

		private static void Patch_Terminal_InitTerminal()
		{
			if (!InitializedTerminal)
			{
				AddSkill(Terminal.commands["raiseskill"]);
				AddSkill(Terminal.commands["resetskill"]);
			}
			static void AddSkill(ConsoleCommand command)
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Expected O, but got Unknown
				ConsoleOptionsFetcher fetcher = command.m_tabOptionsFetcher;
				command.m_tabOptionsFetcher = (ConsoleOptionsFetcher)delegate
				{
					List<string> list = fetcher.Invoke();
					list.AddRange(skills.Values.Select((Skill skill) => skill.internalSkillName));
					return list;
				};
			}
		}

		private static SkillDef? GetSkillDef(SkillType skillType)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (!skills.ContainsKey(skillType))
			{
				return null;
			}
			return skills[skillType].skillDef;
		}

		private static byte[] ReadEmbeddedFileBytes(string name)
		{
			using MemoryStream memoryStream = new MemoryStream();
			Assembly.GetExecutingAssembly().GetManifestResourceStream(Assembly.GetExecutingAssembly().GetName().Name + "." + name).CopyTo(memoryStream);
			return memoryStream.ToArray();
		}

		private static Texture2D loadTexture(string name)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			Texture2D val = new Texture2D(0, 0);
			if (LoadImageMethod == null)
			{
				Debug.LogError((object)"UnityEngine.ImageConversion.LoadImage was not found. Skill icons will not load.");
				return val;
			}
			LoadImageMethod.Invoke(null, new object[2]
			{
				val,
				ReadEmbeddedFileBytes("icons." + name)
			});
			return val;
		}

		private static Sprite loadSprite(string name, int width, int height)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			return Sprite.Create(loadTexture(name), new Rect(0f, 0f, (float)width, (float)height), Vector2.zero);
		}

		private static ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description)
		{
			ConfigEntry<T> val = plugin.Config.Bind<T>(group, name, value, description);
			configSync?.GetType().GetMethod("AddConfigEntry").MakeGenericMethod(typeof(T))
				.Invoke(configSync, new object[1] { val });
			return val;
		}

		private static ConfigEntry<T> config<T>(string group, string name, T value, string description)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()));
		}
	}
	[PublicAPI]
	public static class SkillExtensions
	{
		public static float GetSkillFactor(this Character character, string name)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return character.GetSkillFactor(Skill.fromName(name)) * Skill.skillByName[name].SkillEffectFactor;
		}

		public static float GetSkillFactor(this Skills skills, string name)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return skills.GetSkillFactor(Skill.fromName(name)) * Skill.skillByName[name].SkillEffectFactor;
		}

		public static void RaiseSkill(this Character character, string name, float value = 1f)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			character.RaiseSkill(Skill.fromName(name), value);
		}

		public static void RaiseSkill(this Skills skill, string name, float value = 1f)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			skill.RaiseSkill(Skill.fromName(name), value);
		}

		public static void LowerSkill(this Character character, string name, float factor = 1f)
		{
			character.GetSkills().LowerSkill(name, factor);
		}

		public static void LowerSkill(this Skills skills, string name, float factor)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (factor > 0f && skills.m_skillData.TryGetValue(Skill.fromName(name), out var value))
			{
				Skill obj = value;
				obj.m_level -= value.m_level * factor;
				value.m_accumulator = 0f;
			}
		}
	}
}
namespace OttoAura
{
	[HarmonyPatch]
	internal static class CraftingStationPatches
	{
		internal static CraftingStation? Workbench;

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private static void ZNetSceneAwakePostfix(ZNetScene __instance)
		{
			GameObject prefab = __instance.GetPrefab("piece_workbench");
			Workbench = (((Object)(object)prefab == (Object)null) ? null : prefab.GetComponent<CraftingStation>());
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(InventoryGui), "UpdateRepair")]
		private static void InventoryGuiUpdateRepairPostfix(InventoryGui __instance)
		{
			Player localPlayer = Player.m_localPlayer;
			if (OttoAuraPlugin.PreventCraftingStationRepair.Value != OttoAuraPlugin.Toggle.Off && !((Object)(object)localPlayer == (Object)null) && !((Object)(object)localPlayer.GetCurrentCraftingStation() == (Object)null) && !localPlayer.NoCostCheat())
			{
				((Component)__instance.m_repairPanel).gameObject.SetActive(false);
				((Component)__instance.m_repairPanelSelection).gameObject.SetActive(false);
				((Component)__instance.m_repairButton).gameObject.SetActive(false);
			}
		}
	}
	internal static class DurabilityHold
	{
		internal enum State
		{
			None,
			Holding,
			Expired
		}

		internal const string DeadlineKey = "RepairStation";

		internal const string UseDurabilityKey = "RepairStationUseDurability";

		internal static int MinutesFor(float skillFactor)
		{
			if (!(skillFactor >= 0.5f))
			{
				return 0;
			}
			return (int)(10f * skillFactor);
		}

		internal static void Start(ItemData item, float skillFactor, DateTime now)
		{
			item.m_customData["RepairStation"] = now.AddMinutes(MinutesFor(skillFactor)).ToString(CultureInfo.InvariantCulture);
			item.m_customData["RepairStationUseDurability"] = item.m_shared.m_useDurability.ToString();
		}

		internal static State Refresh(ItemData? item, DateTime now)
		{
			if (item?.m_shared == null || !item.m_customData.TryGetValue("RepairStation", out var value) || !TryReadDeadline(value, out var deadline))
			{
				return State.None;
			}
			if (now <= deadline)
			{
				item.m_shared.m_useDurability = false;
				return State.Holding;
			}
			item.m_customData.Remove("RepairStation");
			if (item.m_customData.TryGetValue("RepairStationUseDurability", out var value2) && bool.TryParse(value2, out var result))
			{
				item.m_shared.m_useDurability = result;
			}
			item.m_customData.Remove("RepairStationUseDurability");
			return State.Expired;
		}

		internal static bool TryReadDeadline(string? value, out DateTime deadline)
		{
			if (!DateTime.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out deadline))
			{
				return DateTime.TryParse(value, out deadline);
			}
			return true;
		}
	}
	[HarmonyPatch]
	internal static class BlacksmithingPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Humanoid), "GetRightItem")]
		private static void HumanoidGetRightItemPostfix(Humanoid __instance)
		{
			if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				Refresh(__instance.m_rightItem, "GetRightItem");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Humanoid), "GetLeftItem")]
		private static void HumanoidGetLeftItemPostfix(Humanoid __instance)
		{
			if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				Refresh(__instance.m_leftItem, "GetLeftItem");
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Humanoid), "IsItemEquiped")]
		private static void HumanoidIsItemEquipedPrefix(Humanoid __instance, ItemData item)
		{
			if (((Character)__instance).IsPlayer() && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				Refresh(item, "IsItemEquiped");
			}
		}

		private static void Refresh(ItemData? item, string caller)
		{
			if (DurabilityHold.Refresh(item, DateTime.Now) == DurabilityHold.State.Expired)
			{
				OttoAuraPlugin.OttoAuraLogger.LogDebug((object)("(" + caller + ") The durability hold on " + item.m_shared.m_name + " ran out."));
			}
		}
	}
	internal static class OttoPayBridge
	{
		private static bool _bound;

		private static MethodInfo? _isAuraPayEnabled;

		private static MethodInfo? _tryWithdraw;

		private static MethodInfo? _registerAuraService;

		private static MethodInfo? _unregisterAuraService;

		private static MethodInfo? _tryDeposit;

		private static MethodInfo? _registerDepositHandler;

		private static MethodInfo? _unregisterDepositHandler;

		internal static bool CanDeposit
		{
			get
			{
				Bind();
				if (_tryDeposit != null)
				{
					return _registerDepositHandler != null;
				}
				return false;
			}
		}

		internal static bool IsAuraPayEnabled()
		{
			Bind();
			if (_isAuraPayEnabled != null)
			{
				return (bool)_isAuraPayEnabled.Invoke(null, null);
			}
			return false;
		}

		internal static bool TryWithdraw(int amount)
		{
			Bind();
			if (_tryWithdraw != null)
			{
				return (bool)_tryWithdraw.Invoke(null, new object[1] { amount });
			}
			return false;
		}

		internal static void RegisterDepositHandler(string name, Func<Inventory, ItemData, int, bool> canDeposit, Func<Inventory, ItemData, int, bool> deposit, Func<Inventory, ItemData, int, string> describe)
		{
			Bind();
			if (CanDeposit)
			{
				_registerDepositHandler.Invoke(null, new object[4] { name, canDeposit, deposit, describe });
			}
		}

		internal static void UnregisterDepositHandler(string name)
		{
			Bind();
			_unregisterDepositHandler?.Invoke(null, new object[1] { name });
		}

		internal static bool TryDeposit(int amount)
		{
			Bind();
			if (_tryDeposit != null)
			{
				return (bool)_tryDeposit.Invoke(null, new object[1] { amount });
			}
			return false;
		}

		internal static void RegisterAuraService(string name, Func<string> describe)
		{
			Bind();
			_registerAuraService?.Invoke(null, new object[2] { name, describe });
		}

		internal static void UnregisterAuraService(string name)
		{
			Bind();
			_unregisterAuraService?.Invoke(null, new object[1] { name });
		}

		private static void Bind()
		{
			if (!_bound)
			{
				_bound = true;
				Type type = AccessTools.TypeByName("OttoPay.OttoPayApi");
				_isAuraPayEnabled = ((type == null) ? null : AccessTools.Method(type, "IsAuraPayEnabled", (Type[])null, (Type[])null));
				_tryWithdraw = ((type == null) ? null : AccessTools.Method(type, "TryWithdraw", (Type[])null, (Type[])null));
				if (_isAuraPayEnabled == null || _tryWithdraw == null)
				{
					_isAuraPayEnabled = null;
					_tryWithdraw = null;
					OttoAuraPlugin.OttoAuraLogger.LogWarning((object)"OttoPay's AuraPay API was not found. Paid aura repairs and AuraBoost are off.");
				}
				_registerAuraService = ((type == null) ? null : AccessTools.Method(type, "RegisterAuraService", (Type[])null, (Type[])null));
				_unregisterAuraService = ((type == null) ? null : AccessTools.Method(type, "UnregisterAuraService", (Type[])null, (Type[])null));
				if (_registerAuraService == null || _unregisterAuraService == null)
				{
					_registerAuraService = null;
					_unregisterAuraService = null;
					OttoAuraPlugin.OttoAuraLogger.LogWarning((object)"OttoPay's RegisterAuraService API was not found. The AuraPay tooltip will not list OttoAura's services.");
				}
				_tryDeposit = ((type == null) ? null : AccessTools.Method(type, "TryDeposit", new Type[1] { typeof(int) }, (Type[])null));
				_registerDepositHandler = ((type == null) ? null : AccessTools.Method(type, "RegisterDepositHandler", (Type[])null, (Type[])null));
				_unregisterDepositHandler = ((type == null) ? null : AccessTools.Method(type, "UnregisterDepositHandler", (Type[])null, (Type[])null));
				if (_tryDeposit == null || _registerDepositHandler == null || _unregisterDepositHandler == null)
				{
					_tryDeposit = null;
					_registerDepositHandler = null;
					_unregisterDepositHandler = null;
					OttoAuraPlugin.OttoAuraLogger.LogWarning((object)"OttoPay's deposit API was not found. AuraTrade stays off until OttoPay 1.6.0 is installed.");
				}
			}
		}
	}
	[BepInPlugin("potto007.OttoAura", "OttoAura", "1.5.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency("potto007.OttoPay", "1.5.0")]
	public class OttoAuraPlugin : BaseUnityPlugin
	{
		public enum Toggle
		{
			On = 1,
			Off = 0
		}

		private class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public int? Order;

			[UsedImplicitly]
			public bool? Browsable;

			[UsedImplicitly]
			public string? Category;

			[UsedImplicitly]
			public Action<ConfigEntryBase>? CustomDrawer;
		}

		internal const string ModName = "OttoAura";

		internal const string ModVersion = "1.5.3";

		internal const string Author = "potto007";

		private const string ModGUID = "potto007.OttoAura";

		private static string ConfigFileName = "potto007.OttoAura.cfg";

		private static string ConfigFileFullPath;

		private readonly Harmony _harmony = new Harmony("potto007.OttoAura");

		public static readonly ManualLogSource OttoAuraLogger;

		private static readonly ConfigSync ConfigSync;

		internal static OttoAuraPlugin context;

		internal static bool BlacksmithingInstalled;

		private static ConfigEntry<Toggle> _serverConfigLocked;

		internal static ConfigEntry<Toggle> PreventCraftingStationRepair;

		internal static ConfigEntry<float> HealPerSecond;

		internal static ConfigEntry<float> RepairPercentPerTick;

		internal static ConfigEntry<int> CoinsPerItemTick;

		internal static ConfigEntry<float> TickSeconds;

		internal static ConfigEntry<Toggle> ShowHealText;

		internal static ConfigEntry<Toggle> AuraBoostEnabled;

		internal static ConfigEntry<float> AuraBoostStaminaTrail;

		internal static ConfigEntry<float> AuraBoostStaminaRoad;

		internal static ConfigEntry<Toggle> AuraBoostShowStatusIcon;

		internal static Sprite? AuraBoostSprite;

		internal static ConfigEntry<Toggle> AuraMoveEnabled;

		internal static ConfigEntry<int> AuraMoveCoins;

		internal static ConfigEntry<float> AuraMoveMaxDistance;

		internal static ConfigEntry<Toggle> AuraMoveSupportImmovable;

		internal static ConfigEntry<string> AuraMoveAllowedPrefabs;

		internal static ConfigEntry<string> AuraMoveDeniedPrefabs;

		internal static ConfigEntry<float> AuraMoveShimmerSeconds;

		internal static ConfigEntry<string> AuraMoveGrabEffects;

		internal static ConfigEntry<string> AuraMoveDepartEffects;

		internal static ConfigEntry<string> AuraMoveTravelEffect;

		internal static ConfigEntry<string> AuraMoveArriveEffects;

		internal static ConfigEntry<string> AuraMoveFinishEffects;

		internal static ConfigEntry<KeyboardShortcut> AuraMoveKey;

		internal static ConfigEntry<Toggle> AuraTradeEnabled;

		internal static ConfigEntry<int> AuraTradeFlatFee;

		internal static ConfigEntry<float> AuraTradePercentFee;

		internal static ConfigEntry<string> AuraTradeDeniedItems;

		internal static ConfigEntry<float> AuraTradeShimmerSeconds;

		internal static ConfigEntry<string> AuraTradeDepartEffects;

		internal static ConfigEntry<string> AuraTradeTravelEffect;

		internal static ConfigEntry<string> AuraTradeArriveEffects;

		internal static ConfigEntry<Toggle> AuraDispelEnabled;

		internal static ConfigEntry<float> AuraDispelRadiusScale;

		public void Awake()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Expected O, but got Unknown
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Expected O, but got Unknown
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Expected O, but got Unknown
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Expected O, but got Unknown
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Expected O, but got Unknown
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Expected O, but got Unknown
			//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0437: Unknown result type (might be due to invalid IL or missing references)
			//IL_0442: Expected O, but got Unknown
			//IL_0470: Unknown result type (might be due to invalid IL or missing references)
			//IL_047b: Expected O, but got Unknown
			//IL_04c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d4: Expected O, but got Unknown
			//IL_057e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0589: Expected O, but got Unknown
			context = this;
			ConfigNameMigration.Apply(((BaseUnityPlugin)this).Config, OttoAuraLogger);
			_serverConfigLocked = config("General", "LockConfiguration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only.");
			ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked);
			HealPerSecond = config("Aura", "HealPerSecond", 1f, new ConfigDescription("Health restored each second to a permitted player inside an active ward. 0 turns healing off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>()));
			RepairPercentPerTick = config("Aura", "RepairPercentPerTick", 5f, new ConfigDescription("Percent of an item's maximum durability restored each tick, for worn gear carried by a permitted player inside an active ward. 0 turns repair off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
			CoinsPerItemTick = config("Aura", "CoinsPerItemTick", 1, new ConfigDescription("Coins charged to the OttoPay Merchant Bank balance for each item repaired in a tick. The player must turn AuraPay on in OttoPay. 0 makes repair free.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()));
			TickSeconds = config("Aura", "TickSeconds", 1f, new ConfigDescription("Seconds between aura ticks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 30f), Array.Empty<object>()));
			ShowHealText = config("Aura", "ShowHealText", Toggle.Off, "If on, each heal tick shows a floating heal number.", synchronizedSetting: false);
			PreventCraftingStationRepair = config("CraftingStations", "PreventCraftingStationRepair", Toggle.Off, "If on, players cannot repair items at crafting stations and must use a ward aura.");
			AuraBoostEnabled = config("AuraBoost", "Enabled", Toggle.On, "If on, Merchant Bank members with AuraPay on in OttoPay drain less stamina while running on roads and trails.");
			AuraBoostStaminaTrail = config("AuraBoost", "StaminaUsageTrail", 0.5f, new ConfigDescription("Run stamina drain on dirt paths, wood and metal, as a fraction of vanilla. 1 is vanilla, 0 is no drain.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			AuraBoostStaminaRoad = config("AuraBoost", "StaminaUsageRoad", 0f, new ConfigDescription("Run stamina drain on paved roads and stone, as a fraction of vanilla. 1 is vanilla, 0 is no drain.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			AuraBoostShowStatusIcon = config("AuraBoost", "ShowStatusIcon", Toggle.On, "If on, the AuraBoost icon shows in the status bar while the effect is active.");
			AuraBoostSprite = LoadSprite("auraboost_icon.png");
			AuraMoveEnabled = config("AuraMove", "Enabled", Toggle.On, "If on, the Merchant Guild will move placed objects for a fee while AuraPay is active.");
			AuraMoveCoins = config("AuraMove", "Coins", 5, new ConfigDescription("Coins charged to the Merchant Bank balance per completed move. 0 makes moving free, but AuraPay must still be on.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()));
			AuraMoveMaxDistance = config("AuraMove", "MaxMoveDistance", 15f, new ConfigDescription("How far in metres the destination may sit from where the object stands now.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 64f), Array.Empty<object>()));
			AuraMoveSupportImmovable = config("AuraMove", "SupportIsImmovable", Toggle.On, "If on, non-furniture pieces that carry structural load cannot be moved.");
			AuraMoveAllowedPrefabs = config("AuraMove", "AllowedPrefabs", "wood_fine_stack,blackwood_stack,bone_stack,piece_beehive", "Comma-separated prefab names that skip every eligibility restriction and can always be moved.");
			AuraMoveDeniedPrefabs = config("AuraMove", "DeniedPrefabs", "fire_pit,bonfire,hearth,windmill", "Comma-separated prefab names that can never be moved.");
			AuraMoveShimmerSeconds = config("AuraMove", "ShimmerSeconds", 1.2f, new ConfigDescription("Total duration of the shrink and grow animation. 0 snaps and only plays the stage effects.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
			AuraMoveGrabEffects = config("AuraMove", "GrabEffects", "fx_summon_start,sfx_staffspiritcaller_cast", "Comma-separated vanilla effect prefabs played for you alone when the Guild takes hold of an object.");
			AuraMoveDepartEffects = config("AuraMove", "DepartEffects", "vfx_Potion_eitr_minor,sfx_OpenPortal", "Comma-separated vanilla effect prefabs played at the old spot as the object leaves it.");
			AuraMoveTravelEffect = config("AuraMove", "TravelEffect", "vfx_pick_wisp", "One vanilla effect prefab flown along an arc from the old spot to the new one during the shimmer. Blank flies nothing.");
			AuraMoveArriveEffects = config("AuraMove", "ArriveEffects", "fx_summon_spirit_spawn,sfx_runestone_activate", "Comma-separated vanilla effect prefabs played at the new spot as the object grows back in, alongside the piece's own place effect.");
			AuraMoveFinishEffects = config("AuraMove", "FinishEffects", "sfx_dverger_heal_finish", "Comma-separated vanilla effect prefabs played at the new spot once the object is whole again.");
			AuraMoveKey = config<KeyboardShortcut>("AuraMove", "MoveKey", new KeyboardShortcut((KeyCode)109, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Keyboard shortcut that takes the hammer out and selects Guild Move, and puts it away again.", synchronizedSetting: false);
			AuraTradeEnabled = config("AuraTrade", "Enabled", Toggle.On, "If on, Merchant Bank members with AuraPay on can sell valuables to the Merchant Guild by dropping them on the Merchant Bank balance, or all at once at the ward, while inside a ward they may use. Needs OttoPay 1.6.0.");
			AuraTradeFlatFee = config("AuraTrade", "FlatFee", 5, new ConfigDescription("Coins the AuraPay network keeps from every trade, however large. Charged once per trade, so one big trade keeps more coins than several small ones.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>()));
			AuraTradePercentFee = config("AuraTrade", "PercentFee", 5f, new ConfigDescription("Percent of a trade's gross worth the AuraPay network keeps on top of FlatFee, rounded up to whole coins.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>()));
			AuraTradeDeniedItems = config("AuraTrade", "DeniedItems", "", "Comma-separated item prefab names the Merchant Guild will not buy, for example Ruby,AmberPearl. Coins are never bought.");
			AuraTradeShimmerSeconds = config("AuraTrade", "ShimmerSeconds", 1.2f, new ConfigDescription("How long a sold valuable takes to shrink away into the ward. 0 plays only the effects.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
			AuraTradeDepartEffects = config("AuraTrade", "DepartEffects", "vfx_Potion_eitr_minor,sfx_OpenPortal", "Comma-separated vanilla effect prefabs played where the sold valuable appears in front of the seller. Every player nearby sees the sale.");
			AuraTradeTravelEffect = config("AuraTrade", "TravelEffect", "vfx_pick_wisp", "One vanilla effect prefab flown with the sold valuable into the ward. Blank flies nothing.");
			AuraTradeArriveEffects = config("AuraTrade", "ArriveEffects", "fx_summon_spirit_spawn,sfx_dverger_heal_finish", "Comma-separated vanilla effect prefabs played at the ward as the sold valuable reaches it.");
			AuraDispelEnabled = config("AuraDispel", "Enabled", Toggle.On, "If on, a lit Wisp Torch also clears the distance fog inside the radius where it clears the Mists. Free, and only changes what players see.");
			AuraDispelRadiusScale = config("AuraDispel", "RadiusScale", 1f, new ConfigDescription("Size of the fog-free bubble, as a multiple of the radius where the torch clears the Mists.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 3f), Array.Empty<object>()));
			BlacksmithingInstalled = Chainloader.PluginInfos.TryGetValue("org.bepinex.plugins.blacksmithing", out var value) && value != null;
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			_harmony.PatchAll(executingAssembly);
			SetupWatcher();
			OttoPayBridge.RegisterAuraService("AuraBoost", () => (AuraBoostEnabled.Value != Toggle.Off) ? "AuraBoost lightens your feet on roads and trails." : "");
			OttoPayBridge.RegisterAuraService("AuraMove", delegate
			{
				if (AuraMoveEnabled.Value == Toggle.Off)
				{
					return "";
				}
				int value2 = AuraMoveCoins.Value;
				string text = ((value2 > 0) ? $"for {value2} coins" : "for free");
				return "AuraMove: open the hammer's Merchant Guild tab or press " + MoveTargeting.KeyLabel + ", then click a chest or piece of furniture to have the Merchant Guild move it a short way " + text + ".";
			});
			OttoPayBridge.RegisterAuraService("AuraTrade", () => (AuraTradeEnabled.Value == Toggle.Off || !OttoPayBridge.CanDeposit) ? "" : string.Format("AuraTrade: inside a ward you may use, drop a valuable on your Merchant Bank balance to sell it, or press {0} on the ward to sell every valuable you carry. AuraPay keeps {1} coins plus {2:0.##}% of each sale, so fewer, larger sales keep more.", Localization.instance.Localize("$KEY_AltPlace + $KEY_Use"), AuraTradeFlatFee.Value, AuraTradePercentFee.Value));
			OttoPayBridge.RegisterAuraService("AuraDispel", () => (AuraDispelEnabled.Value != Toggle.Off) ? "AuraDispel: a lit Wisp Torch dispels the fog around it, not just the Mists." : "");
			AuraTradeController.Register();
		}

		public void Start()
		{
			AuraBoostEffect.Init();
			AuraMoveController.Init();
			FogBubbles.Init();
		}

		private void Update()
		{
			WardAura.Update(Time.deltaTime);
			AuraBoostEffect.Tick();
			AuraMoveController.Tick();
		}

		private static Sprite? LoadSprite(string name)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			MethodInfo methodInfo = AccessTools.Method("UnityEngine.ImageConversion:LoadImage", new Type[2]
			{
				typeof(Texture2D),
				typeof(byte[])
			}, (Type[])null);
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			using Stream stream = executingAssembly.GetManifestResourceStream(executingAssembly.GetName().Name + ".assets." + name);
			if (methodInfo == null || stream == null)
			{
				OttoAuraLogger.LogError((object)("Could not load the " + name + " icon."));
				return null;
			}
			using MemoryStream memoryStream = new MemoryStream();
			stream.CopyTo(memoryStream);
			Texture2D val = new Texture2D(0, 0);
			methodInfo.Invoke(null, new object[2]
			{
				val,
				memoryStream.ToArray()
			});
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), Vector2.zero);
		}

		internal static void AutoDoc()
		{
		}

		private void OnDestroy()
		{
			OttoPayBridge.UnregisterAuraService("AuraBoost");
			OttoPayBridge.UnregisterAuraService("AuraMove");
			OttoPayBridge.UnregisterAuraService("AuraTrade");
			OttoPayBridge.UnregisterAuraService("AuraDispel");
			AuraTradeController.Unregister();
			AuraMoveController.Shutdown();
			AuraBoostEffect.Shutdown();
			FogBubbles.Shutdown();
			((BaseUnityPlugin)this).Config.Save();
		}

		private void SetupWatcher()
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			fileSystemWatcher.Changed += ReadConfigValues;
			fileSystemWatcher.Created += ReadConfigValues;
			fileSystemWatcher.Renamed += ReadConfigValues;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(ConfigFileFullPath))
			{
				return;
			}
			try
			{
				OttoAuraLogger.LogDebug((object)"ReadConfigValues called");
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch
			{
				OttoAuraLogger.LogError((object)("There was an issue loading your " + ConfigFileName));
				OttoAuraLogger.LogError((object)"Please check your config entries for spelling and format!");
			}
		}

		private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags);
			ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(ConfigName.Section(group), ConfigName.Key(name), value, val);
			ConfigSync.AddConfigEntry<T>(val2).SynchronizedConfig = synchronizedSetting;
			return val2;
		}

		private ConfigEntry<T> config<T>(string group, string name, T value, string description, bool synchronizedSetting = true)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
		}

		static OttoAuraPlugin()
		{
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
			OttoAuraLogger = Logger.CreateLogSource("OttoAura");
			ConfigSync = new ConfigSync("potto007.OttoAura")
			{
				DisplayName = "OttoAura",
				CurrentVersion = "1.5.3",
				MinimumRequiredVersion = "1.5.3",
				ModRequired = false
			};
			context = null;
			_serverConfigLocked = null;
			PreventCraftingStationRepair = null;
			HealPerSecond = null;
			RepairPercentPerTick = null;
			CoinsPerItemTick = null;
			TickSeconds = null;
			ShowHealText = null;
			AuraBoostEnabled = null;
			AuraBoostStaminaTrail = null;
			AuraBoostStaminaRoad = null;
			AuraBoostShowStatusIcon = null;
			AuraMoveEnabled = null;
			AuraMoveCoins = null;
			AuraMoveMaxDistance = null;
			AuraMoveSupportImmovable = null;
			AuraMoveAllowedPrefabs = null;
			AuraMoveDeniedPrefabs = null;
			AuraMoveShimmerSeconds = null;
			AuraMoveGrabEffects = null;
			AuraMoveDepartEffects = null;
			AuraMoveTravelEffect = null;
			AuraMoveArriveEffects = null;
			AuraMoveFinishEffects = null;
			AuraMoveKey = null;
			AuraTradeEnabled = null;
			AuraTradeFlatFee = null;
			AuraTradePercentFee = null;
			AuraTradeDeniedItems = null;
			AuraTradeShimmerSeconds = null;
			AuraTradeDepartEffects = null;
			AuraTradeTravelEffect = null;
			AuraTradeArriveEffects = null;
			AuraDispelEnabled = null;
			AuraDispelRadiusScale = null;
		}
	}
	internal static class WardAura
	{
		private const float EmptyBalanceMessageSeconds = 30f;

		private static readonly List<ItemData> _wornItems = new List<ItemData>();

		private static readonly List<ItemData> _repairedItems = new List<ItemData>();

		private static float _elapsed;

		private static float _lastEmptyBalanceMessage = -1000f;

		internal static bool IsPaidRepair => OttoAuraPlugin.CoinsPerItemTick.Value > 0;

		internal static void Update(float deltaTime)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead())
			{
				_elapsed = 0f;
				return;
			}
			_elapsed += deltaTime;
			if (!(_elapsed < OttoAuraPlugin.TickSeconds.Value))
			{
				float elapsed = _elapsed;
				_elapsed = 0f;
				if (!((Object)(object)FindAuraWard(localPlayer) == (Object)null))
				{
					Heal(localPlayer, elapsed);
					Repair(localPlayer);
				}
			}
		}

		internal static PrivateArea? FindAuraWard(Player player)
		{
			//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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)player).transform.position;
			foreach (PrivateArea allArea in PrivateArea.m_allAreas)
			{
				if (!((Object)(object)allArea == (Object)null) && (int)allArea.m_ownerFaction == 0 && allArea.IsEnabled() && allArea.IsInside(position, 0f) && allArea.HaveLocalAccess())
				{
					return allArea;
				}
			}
			return null;
		}

		internal static void CollectRepairable(Inventory inventory, List<ItemData> worn)
		{
			worn.Clear();
			inventory.GetWornItems(worn);
			worn.RemoveAll((ItemData item) => !item.m_shared.m_canBeReparied);
		}

		internal static void RepairStep(List<ItemData> worn, float percent, List<ItemData> repaired)
		{
			repaired.Clear();
			foreach (ItemData item in worn)
			{
				float maxDurability = item.GetMaxDurability();
				item.m_durability = Mathf.Min(maxDurability, item.m_durability + maxDurability * percent / 100f);
				if (item.m_durability >= maxDurability)
				{
					repaired.Add(item);
				}
			}
		}

		internal static string HoverLine(PrivateArea area)
		{
			return HoverLine(OttoAuraPlugin.RepairPercentPerTick.Value, OttoAuraPlugin.HealPerSecond.Value, OttoAuraPlugin.CoinsPerItemTick.Value, area.m_radius);
		}

		internal static string HoverLine(float repairPercent, float healPerSecond, int coinsPerItem, float radius)
		{
			bool flag = repairPercent > 0f;
			bool flag2 = healPerSecond > 0f;
			string arg = ((flag && flag2) ? "heals you and repairs your gear" : (flag ? "repairs your gear" : (flag2 ? "heals you" : "is idle")));
			string arg2 = ((flag && coinsPerItem > 0) ? ", paid through AuraPay" : "");
			return $"\n<color=#8FD7FF>Aura {arg} within {radius:0} m{arg2}</color>";
		}

		private static void Heal(Player player, float elapsed)
		{
			float num = OttoAuraPlugin.HealPerSecond.Value * elapsed;
			if (!(num <= 0f) && !(((Character)player).GetHealth() >= ((Character)player).GetMaxHealth()))
			{
				((Character)player).Heal(num, OttoAuraPlugin.ShowHealText.Value == OttoAuraPlugin.Toggle.On);
			}
		}

		private static void Repair(Player player)
		{
			float value = OttoAuraPlugin.RepairPercentPerTick.Value;
			if (value <= 0f)
			{
				return;
			}
			CollectRepairable(((Humanoid)player).GetInventory(), _wornItems);
			if (_wornItems.Count == 0 || (IsPaidRepair && !TryPay(player, OttoAuraPlugin.CoinsPerItemTick.Value * _wornItems.Count)))
			{
				return;
			}
			RepairStep(_wornItems, value, _repairedItems);
			foreach (ItemData repairedItem in _repairedItems)
			{
				OnFullyRepaired(player, repairedItem);
			}
		}

		private static void OnFullyRepaired(Player player, ItemData item)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			if (OttoAuraPlugin.BlacksmithingInstalled)
			{
				DurabilityHold.Start(item, ((Character)player).GetSkillFactor(Skill.fromName("Blacksmithing")), DateTime.Now);
			}
			((Character)player).Message((MessageType)1, Localization.instance.Localize("$msg_repaired", new string[1] { item.m_shared.m_name }), 0, (Sprite)null, false);
			CraftingStation workbench = CraftingStationPatches.Workbench;
			if ((Object)(object)workbench != (Object)null)
			{
				workbench.m_repairItemDoneEffects.Create(((Component)player).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
			}
		}

		private static bool TryPay(Player player, int cost)
		{
			if (!OttoPayBridge.IsAuraPayEnabled())
			{
				return false;
			}
			if (OttoPayBridge.TryWithdraw(cost))
			{
				return true;
			}
			if (Time.time - _lastEmptyBalanceMessage > 30f)
			{
				((Character)player).Message((MessageType)1, "Your Merchant Bank balance is empty. The aura cannot repair your gear.", 0, (Sprite)null, false);
				_lastEmptyBalanceMessage = Time.time;
			}
			return false;
		}
	}
	[HarmonyPatch]
	internal static class WardAuraPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(PrivateArea), "GetHoverText")]
		private static void PrivateAreaGetHoverTextPostfix(PrivateArea __instance, ref string __result)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (!string.IsNullOrEmpty(__result) && !((Object)(object)Player.m_localPlayer == (Object)null) && (int)__instance.m_ownerFaction == 0 && __instance.IsEnabled() && __instance.HaveLocalAccess())
			{
				__result += WardAura.HoverLine(__instance);
				__result += AuraTradeController.HoverLine(__instance);
			}
		}
	}
}
namespace OttoAura.Config
{
	public static class ConfigName
	{
		public const string DefaultSection = "General";

		private static readonly Regex OrdinalPrefix = new Regex("^\\s*\\d+(?:\\.\\d+)*\\s*-\\s*(?=\\S)");

		public static string Section(string name)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return "General";
			}
			string text = Normalize(OrdinalPrefix.Replace(name, string.Empty, 1));
			if (text.Length != 0)
			{
				return text;
			}
			return "General";
		}

		public static string Key(string name)
		{
			return Normalize(name);
		}

		internal static string Normalize(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return name;
			}
			StringBuilder stringBuilder = new StringBuilder(name.Length);
			if (name[0] == '_')
			{
				stringBuilder.Append('_');
			}
			bool flag = true;
			foreach (char c in name)
			{
				if (!char.IsLetterOrDigit(c))
				{
					flag = true;
					continue;
				}
				stringBuilder.Append(flag ? char.ToUpperInvariant(c) : c);
				flag = false;
			}
			return stringBuilder.ToString();
		}
	}
	public static class ConfigNameMigration
	{
		public static void Apply(ConfigFile file, ManualLogSource? logger)
		{
			try
			{
				string configFilePath = file.ConfigFilePath;
				if (string.IsNullOrEmpty(configFilePath) || !File.Exists(configFilePath))
				{
					return;
				}
				string[] array = File.ReadAllLines(configFilePath);
				HashSet<string> present = CollectNormalizedNames(array);
				HashSet<string> seen = new HashSet<string>();
				List<string> list = new List<string>();
				string section = string.Empty;
				bool flag = false;
				for (int i = 0; i < array.Length; i++)
				{
					string text = SectionName(array[i]);
					if (text != null)
					{
						section = ConfigName.Section(text);
					}
					string text2 = DuplicateKey(array[i], section, present, seen);
					if (text2 != null)
					{
						if (logger != null)
						{
							logger.LogWarning((object)("Dropping the stale duplicate " + text2));
						}
						flag = true;
						continue;
					}
					string text3 = RewriteLine(array[i]);
					list.Add(text3 ?? array[i]);
					if (text3 != null)
					{
						flag = true;
					}
				}
				array = list.ToArray();
				if (!flag)
				{
					return;
				}
				StringBuilder stringBuilder = new StringBuilder();
				string[] array2 = array;
				foreach (string value in array2)
				{
					stringBuilder.Append(value).Append(Environment.NewLine);
				}
				string text4 = configFilePath + ".premigration.bak";
				File.Copy(configFilePath, text4, overwrite: true);
				File.WriteAllText(configFilePath, stringBuilder.ToString());
				if (logger != null)
				{
					logger.LogInfo((object)("Migrated config names to PascalCase: " + configFilePath));
				}
				try
				{
					file.Reload();
				}
				catch (Exception arg)
				{
					File.Copy(text4, configFilePath, overwrite: true);
					if (logger != null)
					{
						logger.LogWarning((object)$"Config name migration rolled back: {arg}");
					}
				}
				finally
				{
					TryDelete(text4, logger);
				}
			}
			catch (Exception arg2)
			{
				if (logger != null)
				{
					logger.LogWarning((object)$"Config name migration skipped: {arg2}");
				}
			}
		}

		private static string? SectionName(string line)
		{
			string text = line.Trim();
			if (text.Length >= 2 && text[0] == '[' && text[text.Length - 1] == ']')
			{
				return text.Substring(1, text.Length - 2);
			}
			return null;
		}

		private static string? KeyName(string line)
		{
			string text = line.Trim();
			if (text.Length == 0 || text[0] == '#' || SectionName(line) != null)
			{
				return null;
			}
			int num = line.IndexOf('=');
			if (num < 0)
			{
				return null;
			}
			string text2 = line.Substring(0, num).Trim();
			if (text2.Length != 0)
			{
				return text2;
			}
			return null;
		}

		private static HashSet<string> CollectNormalizedNames(string[] lines)
		{
			HashSet<string> hashSet = new HashSet<string>();
			string text = string.Empty;
			foreach (string line in lines)
			{
				string text2 = SectionName(line);
				if (text2 != null)
				{
					text = ConfigName.Section(text2);
					continue;
				}
				string text3 = KeyName(line);
				if (text3 != null && ConfigName.Key(text3) == text3)
				{
					hashSet.Add(text + "/" + text3);
				}
			}
			return hashSet;
		}

		private static string? DuplicateKey(string line, string section, HashSet<string> present, HashSet<string> seen)
		{
			string text = KeyName(line);
			if (text == null)
			{
				return null;
			}
			string text2 = ConfigName.Key(text);
			if (text2.Length == 0)
			{
				return null;
			}
			string item = section + "/" + text2;
			if (text2 != text && present.Contains(item))
			{
				return section + "/" + text;
			}
			if (!seen.Add(item))
			{
				return section + "/" + text;
			}
			return null;
		}

		private static void TryDelete(string path, ManualLogSource? logger)
		{
			try
			{
				File.Delete(path);
			}
			catch (Exception ex)
			{
				if (logger != null)
				{
					logger.LogWarning((object)("Could not remove the migration backup " + path + ": " + ex.Message));
				}
			}
		}

		private static string? RewriteLine(string line)
		{
			string text = line.Trim();
			if (text.Length == 0 || text[0] == '#')
			{
				return null;
			}
			if (text.Length >= 2 && text[0] == '[' && text[text.Length - 1] == ']')
			{
				string text2 = text.Substring(1, text.Length - 2);
				string text3 = ConfigName.Section(text2);
				if (text3.Length == 0 || text3 == text2)
				{
					return null;
				}
				return Indent(line) + "[" + text3 + "]" + TrailingSpace(line);
			}
			int num = line.IndexOf('=');
			if (num < 0)
			{
				return null;
			}
			string text4 = line.Substring(0, num);
			string text5 = text4.Trim();
			string text6 = ConfigName.Key(text5);
			if (text5.Length == 0 || text6.Length == 0 || text6 == text5)
			{
				return null;
			}
			return Indent(text4) + text6 + TrailingSpace(text4) + line.Substring(num);
		}

		private static string Indent(string line)
		{
			int i;
			for (i = 0; i < line.Length && char.IsWhiteSpace(line[i]); i++)
			{
			}
			return line.Substring(0, i);
		}

		private static string TrailingSpace(string line)
		{
			int num = line.Length;
			while (num > 0 && char.IsWhiteSpace(line[num - 1]))
			{
				num--;
			}
			return line.Substring(num);
		}
	}
}
namespace OttoAura.AuraTrade
{
	internal static class AuraTradeController
	{
		internal const string HandlerName = "Sell to the Merchant Guild";

		private static readonly List<TradeLot> _lots = new List<TradeLot>();

		internal static void Register()
		{
			OttoPayBridge.RegisterDepositHandler("Sell to the Merchant Guild", CanSell, Sell, Describe);
		}

		internal static void Unregister()
		{
			OttoPayBridge.UnregisterDepositHandler("Sell to the Merchant Guild");
		}

		internal static bool IsAvailable(Player? player)
		{
			if ((Object)(object)player != (Object)null && OttoAuraPlugin.AuraTradeEnabled.Value == OttoAuraPlugin.Toggle.On && OttoPayBridge.CanDeposit && OttoPayBridge.IsAuraPayEnabled())
			{
				return (Object)(object)WardAura.FindAuraWard(player) != (Object)null;
			}
			return false;
		}

		internal static bool IsTradingPost(PrivateArea? area)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)area != (Object)null && (int)area.m_ownerFaction == 0 && area.IsEnabled())
			{
				return area.HaveLocalAccess();
			}
			return false;
		}

		private static bool CanSell(Inventory inventory, ItemData item, int amount)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && amount > 0 && inventory == ((Humanoid)localPlayer).GetInventory() && TradeValuation.IsValuable(item))
			{
				return IsAvailable(localPlayer);
			}
			return false;
		}

		private static string Describe(Inventory inventory, ItemData item, int amount)
		{
			TradeValuation.Quote quote = TradeValuation.QuoteFor(TradeValuation.Worth(item, amount));
			string text = WhatFor(item, amount);
			if (!quote.Tradeable)
			{
				return RefusalFor(text, quote);
			}
			return "Click to sell " + text + ".\n\n" + $"Worth: {quote.Gross} coins\n" + $"AuraPay fee: {quote.Fee} coins\n" + $"To your balance: {quote.Net} coins\n\n" + $"The fee is {OttoAuraPlugin.AuraTradeFlatFee.Value} coins plus {OttoAuraPlugin.AuraTradePercentFee.Value:0.##}% of each sale, so fewer, larger sales keep more.";
		}

		private static bool Sell(Inventory inventory, ItemData item, int amount)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !CanSell(inventory, item, amount) || amount > item.m_stack || !inventory.ContainsItem(item))
			{
				return false;
			}
			PrivateArea val = WardAura.FindAuraWard(localPlayer);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			_lots.Clear();
			_lots.Add(new TradeLot(item, amount));
			return Complete(localPlayer, val, WhatFor(item, amount));
		}

		internal static bool SellAll(Player player, PrivateArea ward)
		{
			_lots.Clear();
			int num = 0;
			foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems())
			{
				if (TradeValuation.IsValuable(allItem))
				{
					_lots.Add(new TradeLot(allItem, allItem.m_stack));
					num += allItem.m_stack;
				}
			}
			if (num == 0)
			{
				Tell(player, "You carry nothing the Merchant Guild will buy.");
				return true;
			}
			Complete(player, ward, (num == 1) ? "1 valuable" : $"{num} valuables");
			return true;
		}

		internal static string HoverLine(PrivateArea ward)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!IsAvailable(localPlayer) || !IsTradingPost(ward))
			{
				return "";
			}
			long num = 0L;
			foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems())
			{
				if (TradeValuation.IsValuable(allItem))
				{
					num += TradeValuation.Worth(allItem, allItem.m_stack);
				}
			}
			if (num == 0L)
			{
				return "";
			}
			TradeValuation.Quote quote = TradeValuation.QuoteFor(num);
			string text = "[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>]";
			string text2 = (quote.Tradeable ? $"\n{text} Sell all valuables: {quote.Gross} worth, {quote.Fee} fee, {quote.Net} to your balance" : $"\n{text} Sell all valuables: the {quote.Fee} coin fee would take all {quote.Gross} they are worth");
			return Localization.instance.Localize(text2);
		}

		private static bool Complete(Player player, PrivateArea ward, string what)
		{
			SaleResult saleResult = TradeSale.Complete(((Humanoid)player).GetInventory(), _lots, TradeValuation.CurrentFees(), new PlayerTradeDesk(player));
			TradeValuation.Quote quote = saleResult.Quote;
			switch (saleResult.Outcome)
			{
			case SaleOutcome.Sold:
				TradeEffects.Broadcast(player, ward, saleResult.MostValuable);
				Tell(player, $"The Merchant Guild bought {what} for {quote.Gross} coins. AuraPay kept {quote.Fee}, and {quote.Net} went to your balance.");
				return true;
			case SaleOutcome.Untradeable:
				Tell(player, RefusalFor(what, quote));
				return false;
			case SaleOutcome.LostTrack:
				Tell(player, "The Merchant Guild lost track of your valuables. Nothing was sold.");
				return false;
			default:
				Tell(player, "The Merchant Bank refused the deposit. Your valuables are back in your pack.");
				return false;
			}
		}

		private static string WhatFor(ItemData item, int amount)
		{
			string text = Localization.instance.Localize(item.m_shared.m_name);
			if (amount <= 1)
			{
				return text;
			}
			return $"{amount} {text}";
		}

		private static string RefusalFor(string what, TradeValuation.Quote quote)
		{
			return $"{what} is worth {quote.Gross} coins, and the AuraPay fee of {quote.Fee} would take all of it. Sell more at once.";
		}

		private static void Tell(Player player, string message)
		{
			((Character)player).Message((MessageType)1, message, 0, (Sprite)null, false);
		}
	}
	internal sealed class PlayerTradeDesk : ITradeDesk
	{
		private readonly Player _player;

		internal PlayerTradeDesk(Player player)
		{
			_player = player;
		}

		public bool TryDeposit(int coins)
		{
			return OttoPayBridge.TryDeposit(coins);
		}

		public void Drop(ItemData item)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)_player).transform;
			ItemDrop.DropItem(item, item.m_stack, transform.position + transform.forward + Vector3.up, transform.rotation);
		}
	}
	[HarmonyPatch]
	internal static class AuraTradePatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(PrivateArea), "Interact")]
		private static bool PrivateAreaInteractPrefix(PrivateArea __instance, Humanoid human, bool hold, bool alt, ref bool __result)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			if (hold || !alt || (Object)(object)human != (Object)(object)Player.m_localPlayer || !AuraTradeController.IsAvailable(Player.m_localPlayer) || !AuraTradeController.IsTradingPost(__instance))
			{
				return true;
			}
			__result = AuraTradeController.SellAll((Player)human, __instance);
			return false;
		}
	}
	internal static class TradeEffects
	{
		internal const string RpcName = "OttoAura_TradeEffect";

		private const float ScaleEpsilon = 0.02f;

		private const float ArcHeight = 1.5f;

		private const float SpinDegreesPerSecond = 360f;

		private const float AudibleRange = 100f;

		internal static void Register()
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsDedicated() && ZRoutedRpc.instance != null && !ZRoutedRpc.instance.m_functions.ContainsKey(StringExtensionMethods.GetStableHashCode("OttoAura_TradeEffect")))
			{
				ZRoutedRpc.instance.Register<Vector3, Vector3, string>("OttoAura_TradeEffect", (Action<long, Vector3, Vector3, string>)RPC_TradeEffect);
			}
		}

		internal static void Broadcast(Player seller, PrivateArea ward, ItemData item)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)seller).transform;
			Vector3 val = transform.position + Vector3.up * 1.3f + transform.forward * 0.7f;
			Vector3 val2 = ((Component)ward).transform.position + Vector3.up * 1.5f;
			string text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : "");
			Play(val, val2, text);
			if (ZRoutedRpc.instance != null)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "OttoAura_TradeEffect", new object[3] { val, val2, text });
			}
		}

		private static void RPC_TradeEffect(long sender, Vector3 from, Vector3 to, string prefab)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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)
			if (ZRoutedRpc.instance != null && sender != ZRoutedRpc.instance.m_id && !((Object)(object)ZNetScene.instance == (Object)null))
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && !(Vector3.Distance(((Component)localPlayer).transform.position, from) > 100f))
				{
					Play(from, to, prefab);
				}
			}
		}

		private static void Play(Vector3 from, Vector3 to, string prefab)
		{
			//IL_000a: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			MoveEffects.Spawn(OttoAuraPlugin.AuraTradeDepartEffects.Value, from, Quaternion.identity, isGrab: false);
			float num = Mathf.Max(0f, OttoAuraPlugin.AuraTradeShimmerSeconds.Value);
			if (num <= 0f)
			{
				MoveEffects.Spawn(OttoAuraPlugin.AuraTradeArriveEffects.Value, to, Quaternion.identity, isGrab: false);
				return;
			}
			GameObject val = MoveEffects.SpawnOne(prefab, from, Quaternion.identity, isGrab: false);
			if ((Object)(object)val != (Object)null)
			{
				MakeInert(val);
			}
			GameObject wisp = MoveEffects.SpawnOne(MoveEffects.FirstName(OttoAuraPlugin.AuraTradeTravelEffect.Value), from, Quaternion.identity, isGrab: false);
			((MonoBehaviour)OttoAuraPlugin.context).StartCoroutine(Carry(val, wisp, from, to, num));
		}

		private static void MakeInert(GameObject visual)
		{
			Rigidbody[] componentsInChildren = visual.GetComponentsInChildren<Rigidbody>();
			foreach (Rigidbody obj in componentsInChildren)
			{
				obj.isKinematic = true;
				obj.detectCollisions = false;
			}
			Collider[] componentsInChildren2 = visual.GetComponentsInChildren<Collider>();
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				componentsInChildren2[i].enabled = false;
			}
			MonoBehaviour[] componentsInChildren3 = visual.GetComponentsInChildren<MonoBehaviour>();
			foreach (MonoBehaviour val in componentsInChildren3)
			{
				if (val is ItemDrop || val is Floating)
				{
					((Behaviour)val).enabled = false;
				}
			}
		}

		private static IEnumerator Carry(GameObject? visual, GameObject? wisp, Vector3 from, Vector3 to, float seconds)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 scale = (((Object)(object)visual != (Object)null) ? visual.transform.localScale : Vector3.one);
			float elapsed = 0f;
			while (elapsed < seconds)
			{
				elapsed += Time.deltaTime;
				float num = Mathf.Clamp01(elapsed / seconds);
				Vector3 position = Vector3.Lerp(from, to, num);
				position.y += 1.5f * Mathf.Sin(num * (float)Math.PI);
				if ((Object)(object)visual != (Object)null)
				{
					visual.transform.position = position;
					visual.transform.localScale = Vector3.Lerp(scale, scale * 0.02f, num);
					visual.transform.Rotate(0f, 360f * Time.deltaTime, 0f);
				}
				if ((Object)(object)wisp != (Object)null)
				{
					wisp.transform.position = position;
				}
				yield return null;
			}
			MoveEffects.DestroyTracked(visual);
			MoveEffects.DestroyTracked(wisp);
			MoveEffects.Spawn(OttoAuraPlugin.AuraTradeArriveEffects.Value, to, Quaternion.identity, isGrab: false);
		}
	}
	[HarmonyPatch]
	internal static class TradeEffectsPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Game), "Start")]
		private static void GameStartPostfix()
		{
			TradeEffects.Register();
		}
	}
	internal readonly struct TradeLot
	{
		internal readonly ItemData Item;

		internal readonly int Amount;

		internal TradeLot(ItemData item, int amount)
		{
			Item = item;
			Amount = amount;
		}
	}
	internal interface ITradeDesk
	{
		bool TryDeposit(int coins);

		void Drop(ItemData item);
	}
	internal enum SaleOutcome
	{
		Sold,
		Untradeable,
		LostTrack,
		DepositRefused
	}
	internal readonly struct SaleResult
	{
		internal readonly SaleOutcome Outcome;

		internal readonly TradeValuation.Quote Quote;

		internal readonly ItemData? MostValuable;

		internal SaleResult(SaleOutcome outcome, TradeValuation.Quote quote, ItemData? mostValuable = null)
		{
			Outcome = outcome;
			Quote = quote;
			MostValuable = mostValuable;
		}
	}
	internal static class TradeSale
	{
		internal static SaleResult Complete(Inventory inventory, IReadOnlyList<TradeLot> lots, TradeFees fees, ITradeDesk desk)
		{
			long num = 0L;
			foreach (TradeLot lot in lots)
			{
				num += TradeValuation.Worth(lot.Item, lot.Amount);
			}
			TradeValuation.Quote quote = TradeValuation.QuoteFor(num, fees);
			if (!quote.Tradeable)
			{
				return new SaleResult(SaleOutcome.Untradeable, quote);
			}
			List<TradeLot> list = new List<TradeLot>(lots.Count);
			foreach (TradeLot lot2 in lots)
			{
				if (!((lot2.Amount == lot2.Item.m_stack) ? inventory.RemoveItem(lot2.Item) : inventory.RemoveItem(lot2.Item, lot2.Amount)))
				{
					Restore(inventory, list, desk);
					return new SaleResult(SaleOutcome.LostTrack, quote);
				}
				list.Add(lot2);
			}
			if (!desk.TryDeposit(quote.Net))
			{
				Restore(inventory, list, desk);
				return new SaleResult(SaleOutcome.DepositRefused, quote);
			}
			return new SaleResult(SaleOutcome.Sold, quote, MostValuable(list));
		}

		private static void Restore(Inventory inventory, List<TradeLot> removed, ITradeDesk desk)
		{
			foreach (TradeLot item2 in removed)
			{
				if (inventory.ContainsItem(item2.Item))
				{
					ItemData item = item2.Item;
					item.m_stack += item2.Amount;
					inventory.Changed(false, false);
				}
				else if (!inventory.AddItem(item2.Item))
				{
					desk.Drop(item2.Item);
				}
			}
		}

		private static ItemData MostValuable(List<TradeLot> lots)
		{
			TradeLot tradeLot = lots[0];
			foreach (TradeLot lot in lots)
			{
				if (TradeValuation.Worth(lot.Item, lot.Amount) > TradeValuation.Worth(tradeLot.Item, tradeLot.Amount))
				{
					tradeLot = lot;
				}
			}
			return tradeLot.Item;
		}
	}
	internal static class TradeTooltip
	{
		private const string ValueTag = "\n$item_value:";

		internal static string Insert(string tooltip, ItemData item, int stack, TradeFees fees)
		{
			StringBuilder stringBuilder = new StringBuilder();
			if (stack > 1)
			{
				AppendQuote(stringBuilder, "AuraTrade each", TradeValuation.QuoteFor(item.m_shared.m_value, fees));
				AppendQuote(stringBuilder, $"AuraTrade stack of {stack}", TradeValuation.QuoteFor(TradeValuation.Worth(item, stack), fees));
			}
			else
			{
				AppendQuote(stringBuilder, "AuraTrade", TradeValuation.QuoteFor(item.m_shared.m_value, fees));
			}
			int num = tooltip.IndexOf("\n$item_value:", StringComparison.Ordinal);
			if (num < 0)
			{
				return tooltip + stringBuilder;
			}
			int num2 = tooltip.IndexOf('\n', num + 1);
			if (num2 >= 0)
			{
				return tooltip.Insert(num2, stringBuilder.ToString());
			}
			return tooltip + stringBuilder;
		}

		private static void AppendQuote(StringBuilder lines, string label, TradeValuation.Quote quote)
		{
			lines.Append(quote.Tradeable ? $"\n{label}: <color=orange>{quote.Gross}</color> worth, <color=orange>{quote.Fee}</color> fee, <color=orange>{quote.Net}</color> net" : $"\n{label}: <color=orange>{quote.Gross}</color> worth, the <color=orange>{quote.Fee}</color> fee takes it all");
		}
	}
	[HarmonyPatch]
	internal static class TradeTooltipPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
		{
			typeof(ItemData),
			typeof(int),
			typeof(bool),
			typeof(float),
			typeof(int),
			typeof(bool)
		})]
		private static void ItemDataGetTooltipPostfix(ItemData item, bool crafting, int stackOverride, bool appending, ref string __result)
		{
			if (!(crafting || appending) && OttoAuraPlugin.AuraTradeEnabled.Value != OttoAuraPlugin.Toggle.Off && OttoPayBridge.CanDeposit && TradeValuation.IsValuable(item))
			{
				__result = TradeTooltip.Insert(__result, item, (stackOverride > 0) ? stackOverride : item.m_stack, TradeValuation.CurrentFees());
			}
		}
	}
	internal readonly struct TradeFees
	{
		internal readonly int Flat;

		internal readonly float Percent;

		internal TradeFees(int flat, float percent)
		{
			Flat = flat;
			Percent = percent;
		}
	}
	internal static class TradeValuation
	{
		internal readonly struct Quote
		{
			internal readonly int Gross;

			internal readonly int Fee;

			internal int Net => Gross - Fee;

			internal bool Tradeable => Net > 0;

			internal Quote(int gross, int fee)
			{
				Gross = gross;
				Fee = fee;
			}
		}

		private const string CoinsName = "$item_coins";

		internal static TradeFees CurrentFees()
		{
			return new TradeFees(OttoAuraPlugin.AuraTradeFlatFee.Value, OttoAuraPlugin.AuraTradePercentFee.Value);
		}

		internal static bool IsValuable(ItemData? item)
		{
			return IsValuable(item, OttoAuraPlugin.AuraTradeDeniedItems.Value);
		}

		internal static bool IsValuable(ItemData? item, string deniedItems)
		{
			if (item == null || item.m_shared.m_value <= 0 || item.m_shared.m_name == "$item_coins")
			{
				return false;
			}
			string prefabName = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : "");
			return !MoveEligibility.IsListed(deniedItems, prefabName);
		}

		internal static long Worth(ItemData item, int stack)
		{
			return (long)item.m_shared.m_value * (long)stack;
		}

		internal static Quote QuoteFor(long gross)
		{
			return QuoteFor(gross, CurrentFees());
		}

		internal static Quote QuoteFor(long gross, TradeFees fees)
		{
			if (gross <= 0 || gross > int.MaxValue)
			{
				return new Quote(0, 0);
			}
			long num = (long)Math.Round((double)Math.Max(0f, fees.Percent) * 100.0);
			long num2 = (gross * num + 9999) / 10000;
			long val = Math.Max(0, fees.Flat) + num2;
			return new Quote((int)gross, (int)Math.Min(val, gross));
		}
	}
}
namespace OttoAura.AuraMove
{
	internal static class AuraMoveController
	{
		private static bool _lastAvailable;

		internal static bool IsAvailable
		{
			get
			{
				if (OttoAuraPlugin.AuraMoveEnabled.Value == OttoAuraPlugin.Toggle.On)
				{
					return OttoPayBridge.IsAuraPayEnabled();
				}
				return false;
			}
		}

		internal static void Init()
		{
			MoveCarry.Drop(rebuildGhost: false);
			_lastAvailable = false;
		}

		internal static void Tick()
		{
			MoveEffects.Tick();
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				MoveCarry.Drop(rebuildGhost: false);
				_lastAvailable = false;
				return;
			}
			bool isAvailable = IsAvailable;
			if (MoveCarry.IsCarrying && !CarryStillValid(localPlayer, isAvailable))
			{
				MoveCarry.Drop(rebuildGhost: true);
			}
			if (isAvailable != _lastAvailable)
			{
				_lastAvailable = isAvailable;
				if (((Character)localPlayer).InPlaceMode())
				{
					localPlayer.UpdateAvailablePiecesList();
				}
			}
			GuildMove.RefreshDescription();
			if (((Character)localPlayer).InPlaceMode() && (Object)(object)localPlayer.m_buildPieces == (Object)(object)GuildMove.HammerTable)
			{
				GuildMove.EnsureTabs(localPlayer.m_buildPieces);
			}
			HandleShortcut(localPlayer, isAvailable);
		}

		internal static void Shutdown()
		{
			MoveCarry.Drop(rebuildGhost: false);
			MoveEffects.StopAll();
			GuildMove.Shutdown();
			_lastAvailable = false;
		}

		internal static bool HandlePlaceClick(Player player)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!IsAvailable)
			{
				MoveCarry.Drop(rebuildGhost: true);
				return false;
			}
			if (!MoveCarry.IsCarrying)
			{
				TryGrab(player);
				return false;
			}
			player.UpdatePlacementGhost(true);
			if (MoveCarry.TooFar)
			{
				((Character)player).Message((MessageType)1, "The Guild will not carry it that far.", 0, (Sprite)null, false);
				return false;
			}
			if ((int)player.m_placementStatus != 0)
			{
				return true;
			}
			ChargeAndCommit(player);
			return false;
		}

		internal static void CancelByPlayer(Player player)
		{
			((Character)player).Message((MessageType)1, "The Merchant Guild lets go.", 0, (Sprite)null, false);
			MoveCarry.Drop(rebuildGhost: true);
		}

		private static void TryGrab(Player player)
		{
			Piece hoveringPiece = player.GetHoveringPiece();
			if ((Object)(object)hoveringPiece == (Object)null)
			{
				return;
			}
			MoveDenial moveDenial = MoveEligibility.Evaluate(hoveringPiece, flashWard: true);
			if (moveDenial != MoveDenial.None)
			{
				string text = MoveEligibility.DenialMessage(moveDenial);
				if (text.Length > 0)
				{
					((Character)player).Message((MessageType)1, text, 0, (Sprite)null, false);
				}
			}
			else if (MoveCarry.Grab(player, hoveringPiece))
			{
				((Character)player).Message((MessageType)1, "The Merchant Guild takes hold of the " + MoveCarry.CarriedName + ".", 0, (Sprite)null, false);
			}
		}

		private static void ChargeAndCommit(Player player)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			Piece source = MoveCarry.Source;
			GameObject placementGhost = player.m_placementGhost;
			if ((Object)(object)source == (Object)null || (Object)(object)placementGhost == (Object)null || !MoveRelocation.CanRequest(source))
			{
				MoveCarry.Drop(rebuildGhost: true);
				return;
			}
			MoveDenial moveDenial = MoveEligibility.Evaluate(source, flashWard: true);
			if (moveDenial != MoveDenial.None)
			{
				string text = MoveEligibility.DenialMessage(moveDenial);
				if (text.Length > 0)
				{
					((Character)player).Message((MessageType)1, text, 0, (Sprite)null, false);
				}
				MoveCarry.Drop(rebuildGhost: true);
				return;
			}
			int num = Mathf.Max(0, OttoAuraPlugin.AuraMoveCoins.Value);
			if (num > 0 && !OttoPayBridge.TryWithdraw(num))
			{
				((Character)player).Message((MessageType)1, "Your Merchant Bank balance is empty. The Merchant Guild does not work for free.", 0, (Sprite)null, false);
				return;
			}
			Vector3 position = placementGhost.transform.position;
			Quaternion rotation = placementGhost.transform.rotation;
			string carriedName = MoveCarry.CarriedName;
			bool num2 = MoveRelocation.Request(source, position, rotation);
			MoveCarry.Drop(rebuildGhost: true);
			if (!num2)
			{
				OttoAuraPlugin.OttoAuraLogger.LogWarning((object)"AuraMove: the move RPC could not be sent after the fee was taken.");
				return;
			}
			string text2 = ((num > 0) ? $"The Guild moves the {carriedName} for {num} coins." : ("The Guild moves the " + carriedName + "."));
			((Character)player).Message((MessageType)1, text2, 0, (Sprite)null, false);
		}

		private static bool CarryStillValid(Player player, bool available)
		{
			//IL_006b: 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)
			if (!available || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || !((Character)player).InPlaceMode())
			{
				return false;
			}
			if ((Object)(object)player.m_buildPieces != (Object)(object)GuildMove.HammerTable || !GuildMove.IsSelectedBy(player))
			{
				return false;
			}
			Piece source = MoveCarry.Source;
			if ((Object)(object)source == (Object)null || (Object)(object)source.m_nview == (Object)null || !source.m_nview.IsValid())
			{
				return false;
			}
			return Vector3.Distance(((Component)player).transform.position, ((Component)source).transform.position) <= OttoAuraPlugin.AuraMoveMaxDistance.Value + player.m_maxPlaceDistance;
		}

		private static void HandleShortcut(Player player, bool available)
		{
			if (!MoveTargeting.ShortcutDown || !available || (Object)(object)GuildMove.PseudoPiece == (Object)null || (Object)(object)GuildMove.HammerTable == (Object)null)
			{
				return;
			}
			if (GuildMove.IsSelectedBy(player))
			{
				MoveCarry.Drop(rebuildGhost: false);
				((Humanoid)player).UnequipItem(((Humanoid)player).GetRightItem(), true);
				return;
			}
			if ((Object)(object)player.m_buildPieces != (Object)(object)GuildMove.HammerTable)
			{
				ItemData val = FindHammer(player);
				if (val == null)
				{
					((Character)player).Message((MessageType)1, "The Merchant Guild works through a hammer, and you have none.", 0, (Sprite)null, false);
					return;
				}
				if (!((Humanoid)player).EquipItem(val, true))
				{
					return;
				}
			}
			player.SetSelectedPiece(GuildMove.PseudoPiece);
		}

		private static ItemData? FindHammer(Player player)
		{
			foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems())
			{
				if ((Object)(object)allItem.m_shared.m_buildPieces == (Object)(object)GuildMove.HammerTable)
				{
					return allItem;
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(Minimap), "SetMapMode")]
	internal static class Minimap_SetMapMode_Patch
	{
		private static bool Prefix(MapMode mode)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			if ((int)mode == 2)
			{
				return !MoveTargeting.ShortcutDown;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Game), "Logout")]
	internal static class Game_Logout_Patch
	{
		private static void Prefix()
		{
			MoveCarry.Drop(rebuildGhost: false);
			MoveEffects.StopAll();
		}
	}
	internal static class GuildMove
	{
		internal const string PrefabName = "OttoAura_GuildMove";

		internal const string PieceLabel = "Guild Move";

		internal const string CategoryLabel = "Merchant Guild";

		internal const PieceCategory Category = (PieceCategory)10;

		private const int CategoryListCount = 11;

		private static GameObject? _prefab;

		private static Piece? _pseudoPiece;

		private static PieceTable? _hammerTable;

		private static bool _warnedNoHammer;

		private static string _describedFor = "";

		private static int _describedCoins = -1;

		private static float _describedDistance = -1f;

		internal static Piece? PseudoPiece => _pseudoPiece;

		internal static PieceTable? HammerTable => _hammerTable;

		internal static bool IsPseudoPiece(Piece? piece)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Invalid comparison between Unknown and I4
			if ((Object)(object)piece != (Object)null && (Object)(object)_pseudoPiece != (Object)null && piece.m_name == "Guild Move")
			{
				return (int)piece.m_category == 10;
			}
			return false;
		}

		internal static bool IsSelectedBy(Player? player)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)_hammerTable == (Object)null || (Object)(object)player.m_buildPieces != (Object)(object)_hammerTable)
			{
				return false;
			}
			return IsPseudoPiece(_hammerTable.GetSelectedPiece());
		}

		internal static void Setup(ObjectDB db)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)db == (Object)null)
			{
				return;
			}
			PieceTable val = ResolveHammerTable(db);
			if (!((Object)(object)val == (Object)null))
			{
				_hammerTable = val;
				if (!((Object)(object)_prefab != (Object)null))
				{
					GameObject val2 = new GameObject("OttoAura_GuildMove");
					val2.SetActive(false);
					Object.DontDestroyOnLoad((Object)(object)val2);
					Piece obj = val2.AddComponent<Piece>();
					obj.m_name = "Guild Move";
					obj.m_description = BuildDescription();
					obj.m_icon = ResolveIcon(db);
					obj.m_category = (PieceCategory)10;
					obj.m_usage = (UsageTagFlags)1;
					obj.m_canBeRemoved = false;
					obj.m_enabled = true;
					obj.m_canRotate = true;
					obj.m_resources = Array.Empty<Requirement>();
					_prefab = val2;
					_pseudoPiece = obj;
				}
			}
		}

		internal static void Shutdown()
		{
			if ((Object)(object)_hammerTable != (Object)null && (Object)(object)_pseudoPiece != (Object)null)
			{
				_hammerTable.m_enabledPieces.Remove(_pseudoPiece);
				_hammerTable.m_availablePieces.Remove(_pseudoPiece);
				if (_hammerTable.m_availablePiecesByCategory.Count > 10)
				{
					_hammerTable.m_availablePiecesByCategory[10].Remove(_pseudoPiece);
				}
				SyncCategory(_hammerTable, ava