Decompiled source of SkyheimCompat v1.1.29

Cjayride.SkyheimCompat.dll

Decompiled 17 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using SimpleJSON;
using UnityEngine;
using UnityEngine.UI;
using skyheim;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyCompany("Cjayride.SkyheimCompat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.29.0")]
[assembly: AssemblyInformationalVersion("1.1.29+b66b04344934edda34df526a79d5b552b71ea3b9")]
[assembly: AssemblyProduct("Cjayride.SkyheimCompat")]
[assembly: AssemblyTitle("Cjayride.SkyheimCompat")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.29.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Cjayride.SkyheimCompat
{
	[HarmonyPatch(typeof(SkyheimAltarPanel), "UpdateGui")]
	internal static class AltarCostHint
	{
		[HarmonyPatch(typeof(SkyheimAltar), "RPC_StopProcess")]
		private static class WatchFinish
		{
			private static void Postfix(SkyheimAltar __instance, bool completed)
			{
				if (completed && Object.op_Implicit((Object)(object)__instance))
				{
					_finishedId = ((Object)__instance).GetInstanceID();
					_finishedAt = Time.unscaledTime;
				}
			}
		}

		private static readonly FieldInfo AltarField = AccessTools.Field(typeof(SkyheimAltarPanel), "_altar");

		private static readonly FieldInfo TimeField = AccessTools.Field(typeof(SkyheimAltarPanel), "_timeText");

		private static readonly PropertyInfo TuningProperty = AccessTools.Property(typeof(SkyheimAltar), "Tuning");

		private const string ImbuedKey = "sh_mod_eitr";

		private static FieldInfo SenealSub;

		private static FieldInfo SenealCurrent;

		private static PropertyInfo SenealText;

		private static Container _container;

		private static SkyheimAltar _altar;

		private static uint _revision = uint.MaxValue;

		private static int _second = int.MinValue;

		private static bool _finishedShown;

		private static string _line;

		private static int _finishedId;

		private static float _finishedAt = -999f;

		private static string _shardPrefab;

		internal static void ApplySeneal(Harmony harmony)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			if (Plugin.SenealUiLoaded())
			{
				Type type = AccessTools.TypeByName("SeneaLUI.Inv.ContainerView");
				MethodInfo methodInfo = AccessTools.Method(type, "Tick", (Type[])null, (Type[])null);
				FieldInfo fieldInfo = AccessTools.Field(type, "_sub");
				FieldInfo fieldInfo2 = AccessTools.Field(AccessTools.TypeByName("SeneaLUI.Inv.Slots"), "Current");
				if (methodInfo == null || fieldInfo == null || fieldInfo2 == null)
				{
					Plugin.LogWarning("SeneaL chest window was not found. Altar shard text stays on Skyheim's own panel.");
					return;
				}
				SenealSub = fieldInfo;
				SenealCurrent = fieldInfo2;
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(AltarCostHint), "SenealTick", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log("Rune Altar requirements show on the SeneaL chest subtitle.");
			}
		}

		private static void SenealTick(object __instance)
		{
			object? obj = SenealCurrent?.GetValue(null);
			Container val = (Container)((obj is Container) ? obj : null);
			if (val == null)
			{
				_container = null;
				return;
			}
			if ((Object)(object)val != (Object)(object)_container)
			{
				_container = val;
				_altar = ((Component)val).GetComponent<SkyheimAltar>();
				if (!Object.op_Implicit((Object)(object)_altar))
				{
					_altar = ((Component)val).GetComponentInParent<SkyheimAltar>();
				}
				_revision = uint.MaxValue;
			}
			if (!Object.op_Implicit((Object)(object)_altar))
			{
				return;
			}
			int num = (_altar.Processing ? Mathf.CeilToInt(_altar.TimeRemaining) : 0);
			bool flag = JustFinished(_altar);
			uint lastRevision = val.m_lastRevision;
			if (lastRevision == _revision && num == _second && flag == _finishedShown)
			{
				return;
			}
			_revision = lastRevision;
			_second = num;
			_finishedShown = flag;
			string text = SenealStatus(_altar);
			if (!(text == _line))
			{
				_line = text;
				if (SenealText == null)
				{
					object obj2 = SenealSub?.GetValue(__instance);
					SenealText = obj2?.GetType().GetProperty("text");
					SenealText?.SetValue(obj2, text, null);
				}
				else
				{
					object obj3 = SenealSub?.GetValue(__instance);
					SenealText.SetValue(obj3, text, null);
				}
			}
		}

		private static string SenealStatus(SkyheimAltar altar)
		{
			if ((Object)(object)altar != (Object)null && altar.Processing)
			{
				return WaitText(altar.TimeRemaining) + " left";
			}
			SkyheimArmorRecipe val = (((Object)(object)altar != (Object)null) ? altar.GetActiveRecipe() : null);
			if (val == null)
			{
				if (!HasImbuedArmor(altar))
				{
					return "Put armor in";
				}
				if (!JustFinished(altar))
				{
					return "Item already imbued";
				}
				return "Finished adding Eitr";
			}
			int num = CountShards(altar);
			string text = ShortWait(val.CraftingTime);
			if (num >= val.EitrShardsRequired)
			{
				return "Close chest, " + text;
			}
			return "Need " + val.EitrShardsRequired + ", have " + num + ", " + text;
		}

		internal static string Status(SkyheimAltar altar)
		{
			if ((Object)(object)altar != (Object)null && altar.Processing)
			{
				return "Imbuing. " + WaitText(altar.TimeRemaining) + " left.";
			}
			SkyheimArmorRecipe val = (((Object)(object)altar != (Object)null) ? altar.GetActiveRecipe() : null);
			if (val == null)
			{
				if (!HasImbuedArmor(altar))
				{
					return "Put a supported armor piece in. The shard cost shows here.";
				}
				if (!JustFinished(altar))
				{
					return "Item already imbued.";
				}
				return "Finished adding Eitr.";
			}
			int num = CountShards(altar);
			string text = WaitText(val.CraftingTime);
			if (num >= val.EitrShardsRequired)
			{
				return "Close the chest to start. Takes " + text + ".";
			}
			return $"Need {val.EitrShardsRequired} Eitr Shards. You have {num}. Takes {text}.";
		}

		private static void Postfix(SkyheimAltarPanel __instance)
		{
			object? obj = AltarField?.GetValue(__instance);
			SkyheimAltar val = (SkyheimAltar)((obj is SkyheimAltar) ? obj : null);
			if (val != null && !val.Processing)
			{
				object? obj2 = TimeField?.GetValue(__instance);
				Text val2 = (Text)((obj2 is Text) ? obj2 : null);
				if (val2 != null)
				{
					val2.horizontalOverflow = (HorizontalWrapMode)0;
					val2.verticalOverflow = (VerticalWrapMode)1;
					val2.text = Status(val);
				}
			}
		}

		private static bool JustFinished(SkyheimAltar altar)
		{
			if (Object.op_Implicit((Object)(object)altar) && ((Object)altar).GetInstanceID() == _finishedId)
			{
				return Time.unscaledTime - _finishedAt < 15f;
			}
			return false;
		}

		private static bool HasImbuedArmor(SkyheimAltar altar)
		{
			Inventory val = (((Object)(object)altar != (Object)null && Object.op_Implicit((Object)(object)altar.Container)) ? ((Container)altar.Container).GetInventory() : null);
			if (val == null)
			{
				return false;
			}
			foreach (ItemData allItem in val.GetAllItems())
			{
				if (allItem?.m_customData != null && allItem.m_customData.ContainsKey("sh_mod_eitr"))
				{
					return true;
				}
			}
			return false;
		}

		private static int CountShards(SkyheimAltar altar)
		{
			if (_shardPrefab == null)
			{
				object? obj = TuningProperty?.GetValue(altar);
				SkyheimAltarTuning val = (SkyheimAltarTuning)((obj is SkyheimAltarTuning) ? obj : null);
				_shardPrefab = (((Object)(object)val != (Object)null) ? val.EitrShardPrefab : "");
			}
			SkyheimAltarContainer container = altar.Container;
			Inventory val2 = ((container != null) ? ((Container)container).GetInventory() : null);
			if (val2 == null || _shardPrefab.Length == 0)
			{
				return 0;
			}
			int num = 0;
			foreach (ItemData allItem in val2.GetAllItems())
			{
				if ((Object)(object)allItem?.m_dropPrefab != (Object)null && ((Object)allItem.m_dropPrefab).name == _shardPrefab)
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}

		private static string ShortWait(float seconds)
		{
			int num = Mathf.Max(0, Mathf.RoundToInt(seconds));
			if (num >= 60 && num % 60 == 0)
			{
				return num / 60 + " min";
			}
			if (num >= 60)
			{
				return num / 60 + "m " + num % 60 + "s";
			}
			return num + "s";
		}

		private static string WaitText(float seconds)
		{
			int num = Mathf.Max(0, Mathf.RoundToInt(seconds));
			if (num >= 60 && num % 60 == 0)
			{
				int num2 = num / 60;
				if (num2 != 1)
				{
					return num2 + " minutes";
				}
				return "1 minute";
			}
			if (num >= 60)
			{
				return num / 60 + " min " + num % 60 + " sec";
			}
			if (num != 1)
			{
				return num + " seconds";
			}
			return "1 second";
		}
	}
	[HarmonyPatch]
	internal static class AltarImbueCompat
	{
		private const string ModTypeKey = "sh_mod_type";

		private const string DefaultExtraRecipes = "ArmorHorseClothChest_T1:20:20:0.2:0.25:240, ArmorHorseClothLegs_T1:15:15:0.1:0.25:240, ArmorHorseClothHelmet_T1:8:10:0.2:0.1:120, ArmorHorseClothChest_T2:25:25:0:0.1:300, ArmorHorseClothLegs_T2:18:15:0:0.1:300, ArmorHorseClothHelmet_T2:10:10:0:0.1:120, rae_OdinHorse_Helmet:6:5:0.2:0.5:60";

		private static ConfigEntry<string> _extraRecipes;

		private static readonly PropertyInfo TuningProperty = AccessTools.Property(typeof(SkyheimAltar), "Tuning");

		internal static void Bind(ConfigFile config)
		{
			_extraRecipes = config.Bind<string>("Altar imbue", "Extra Recipes", "ArmorHorseClothChest_T1:20:20:0.2:0.25:240, ArmorHorseClothLegs_T1:15:15:0.1:0.25:240, ArmorHorseClothHelmet_T1:8:10:0.2:0.1:120, ArmorHorseClothChest_T2:25:25:0:0.1:300, ArmorHorseClothLegs_T2:18:15:0:0.1:300, ArmorHorseClothHelmet_T2:10:10:0:0.1:120, rae_OdinHorse_Helmet:6:5:0.2:0.5:60", "Extra armor the Skyheim altar can eitr-imbue, comma separated. Format per entry: PrefabName:ShardsRequired:MaxEitr:EitrRegen:ArmorPenalty:Seconds (regen and armor penalty are fractions, e.g. 0.2 = 20%). Defaults cover the OdinHorse Skogarmadr (T1) and Drapmadr (T2) sets and the Horse Trophy Helmet. Entries for prefabs Skyheim already supports replace Skyheim's values.");
		}

		[HarmonyPatch(typeof(SkyheimAltarTuning), "RuntimeDeserialize")]
		[HarmonyPostfix]
		private static void RuntimeDeserialize_Postfix(SkyheimAltarTuning __instance)
		{
			if (__instance?.Recipes == null || _extraRecipes == null)
			{
				return;
			}
			int num = 0;
			string[] array = _extraRecipes.Value.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text in array)
			{
				SkyheimArmorRecipe recipe = Parse(text.Trim());
				if (recipe != null)
				{
					__instance.Recipes.RemoveAll((SkyheimArmorRecipe r) => string.Equals(r.SourceItemDrop, recipe.SourceItemDrop, StringComparison.Ordinal));
					__instance.Recipes.Add(recipe);
					num++;
				}
			}
			Plugin.Log($"Altar imbue: {num} extra recipe(s) loaded, {__instance.Recipes.Count} total.");
		}

		private static SkyheimArmorRecipe Parse(string entry)
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Expected O, but got Unknown
			if (entry.Length == 0)
			{
				return null;
			}
			string[] array = entry.Split(new char[1] { ':' });
			if (array.Length != 6 || !int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || !TryFloat(array[2], out var value) || !TryFloat(array[3], out var value2) || !TryFloat(array[4], out var value3) || !TryFloat(array[5], out var value4))
			{
				Plugin.LogWarning("Altar imbue: ignoring malformed recipe '" + entry + "' (expected Prefab:Shards:Eitr:Regen:Armor:Seconds).");
				return null;
			}
			return new SkyheimArmorRecipe
			{
				SourceItemDrop = array[0].Trim(),
				EitrShardsRequired = result,
				EitrModifier = value,
				EitrRegenModifier = value2,
				ArmorModifier = value3,
				CraftingTime = value4
			};
		}

		private static bool TryFloat(string text, out float value)
		{
			return float.TryParse(text.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out value);
		}

		private static SkyheimAltarTuning GetTuning(SkyheimAltar altar)
		{
			object? obj = TuningProperty?.GetValue(altar);
			return (SkyheimAltarTuning)((obj is SkyheimAltarTuning) ? obj : null);
		}

		private static bool Matches(ItemData item, string prefabName, string sharedName)
		{
			if (item?.m_shared == null)
			{
				return false;
			}
			if ((Object)(object)item.m_dropPrefab != (Object)null && ((Object)item.m_dropPrefab).name == prefabName)
			{
				return true;
			}
			if (sharedName != null)
			{
				return item.m_shared.m_name == sharedName;
			}
			return false;
		}

		private static string SharedNameOf(string prefabName)
		{
			GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(prefabName) : null);
			return (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null)?.m_itemData?.m_shared?.m_name;
		}

		private static ItemData FindImbuable(Inventory inventory, SkyheimArmorRecipe recipe)
		{
			string sharedName = SharedNameOf(recipe.SourceItemDrop);
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if (Matches(allItem, recipe.SourceItemDrop, sharedName) && !allItem.m_customData.ContainsKey("sh_mod_type"))
				{
					return allItem;
				}
			}
			return null;
		}

		private static int CountShards(Inventory inventory, string shardPrefab)
		{
			int num = 0;
			foreach (ItemData allItem in inventory.GetAllItems())
			{
				if ((Object)(object)allItem?.m_dropPrefab != (Object)null && ((Object)allItem.m_dropPrefab).name == shardPrefab)
				{
					num += allItem.m_stack;
				}
			}
			return num;
		}

		private static void RemoveShards(Inventory inventory, string shardPrefab, int amount)
		{
			foreach (ItemData item in new List<ItemData>(inventory.GetAllItems()))
			{
				if (amount <= 0)
				{
					break;
				}
				if (!((Object)(object)item?.m_dropPrefab == (Object)null) && !(((Object)item.m_dropPrefab).name != shardPrefab))
				{
					int num = Mathf.Min(item.m_stack, amount);
					inventory.RemoveItem(item, num);
					amount -= num;
				}
			}
		}

		[HarmonyPatch(typeof(SkyheimAltar), "GetActiveRecipe")]
		[HarmonyPrefix]
		private static bool GetActiveRecipe_Prefix(SkyheimAltar __instance, ref SkyheimArmorRecipe __result)
		{
			SkyheimAltarTuning tuning = GetTuning(__instance);
			SkyheimAltarContainer container = __instance.Container;
			Inventory val = ((container != null) ? ((Container)container).GetInventory() : null);
			if (tuning?.Recipes == null || val == null)
			{
				return true;
			}
			__result = null;
			foreach (SkyheimArmorRecipe recipe in tuning.Recipes)
			{
				if (FindImbuable(val, recipe) != null)
				{
					__result = recipe;
					break;
				}
			}
			return false;
		}

		[HarmonyPatch(typeof(SkyheimAltar), "HasEitrShards")]
		[HarmonyPrefix]
		private static bool HasEitrShards_Prefix(SkyheimAltar __instance, SkyheimArmorRecipe recipe, ref bool __result)
		{
			SkyheimAltarTuning tuning = GetTuning(__instance);
			SkyheimAltarContainer container = __instance.Container;
			Inventory val = ((container != null) ? ((Container)container).GetInventory() : null);
			if ((Object)(object)tuning == (Object)null || val == null || recipe == null)
			{
				return true;
			}
			__result = CountShards(val, tuning.EitrShardPrefab) >= recipe.EitrShardsRequired;
			return false;
		}

		[HarmonyPatch(typeof(SkyheimAltar), "CraftItem")]
		[HarmonyPrefix]
		private static bool CraftItem_Prefix(SkyheimAltar __instance)
		{
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			SkyheimAltarTuning tuning = GetTuning(__instance);
			SkyheimAltarContainer container = __instance.Container;
			Inventory val = ((container != null) ? ((Container)container).GetInventory() : null);
			if (tuning?.Recipes == null || val == null)
			{
				return true;
			}
			bool flag = false;
			foreach (SkyheimArmorRecipe recipe in tuning.Recipes)
			{
				ItemData val2 = FindImbuable(val, recipe);
				if (val2 != null && CountShards(val, tuning.EitrShardPrefab) >= recipe.EitrShardsRequired)
				{
					RemoveShards(val, tuning.EitrShardPrefab, recipe.EitrShardsRequired);
					val2.m_customData["sh_mod_type"] = ((object)(ImbueType)0/*cast due to .constrained prefix*/).ToString();
					val2.m_customData["sh_mod_eitr"] = recipe.EitrModifier.ToString();
					val2.m_customData["sh_mod_eitr_regen"] = recipe.EitrRegenModifier.ToString();
					val2.m_customData["sh_mod_armor"] = recipe.ArmorModifier.ToString();
					val2.m_customData["sh_mod_name"] = "Imbued " + val2.m_shared.m_name;
					flag = true;
					Plugin.Log($"Altar imbue: imbued {recipe.SourceItemDrop} (+{recipe.EitrModifier} eitr) using {recipe.EitrShardsRequired} shards.");
				}
			}
			if (flag)
			{
				((Container)container).Save();
			}
			return false;
		}
	}
	internal static class AltarPanelFix
	{
		internal static void Apply(Harmony harmony)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(InventoryGui), "UpdateContainer", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Plugin.LogWarning("InventoryGui.UpdateContainer was not found; altar panel prefix was not replaced.");
				return;
			}
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(AltarPanelFix), "UpdateContainerPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			Plugin.Log("Replaced Skyheim altar UpdateContainer prefix with a null-safe version.");
		}

		private static bool UpdateContainerPrefix()
		{
			SkyheimAltarPanel instance = SkyheimAltarPanel.Instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				return true;
			}
			return !((Component)instance).gameObject.activeSelf;
		}
	}
	[HarmonyPatch(typeof(AssetManager), "LoadItems")]
	internal static class AssetManager_LoadItems_Guard
	{
		private const string SentinelPrefab = "bonemass_drop";

		private static bool Prefix(ObjectDB db)
		{
			if ((Object)(object)db == (Object)null)
			{
				return true;
			}
			if ((Object)(object)db.GetItemPrefab("bonemass_drop") != (Object)null)
			{
				Plugin.Log("Skipped Skyheim LoadItems; ObjectDB already has bonemass_drop.");
				return false;
			}
			return true;
		}
	}
	internal static class CooldownPrefabFix
	{
		internal static void Replace()
		{
			if (SkyheimCooldown.Instance != null)
			{
				GameObject value = Build();
				AccessTools.Field(typeof(SkyheimCooldown), "_cooldownPrefab")?.SetValue(SkyheimCooldown.Instance, value);
				Plugin.Log("Replaced Skyheim item_cooldown prefab with a runtime overlay (fixes missing SkyheimCooldownItem).");
			}
		}

		private static GameObject Build()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("item_cooldown", new Type[1] { typeof(RectTransform) });
			Object.DontDestroyOnLoad((Object)(object)val);
			val.SetActive(false);
			Stretch(val.GetComponent<RectTransform>());
			GameObject val2 = new GameObject("swipe", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val2.transform.SetParent(val.transform, false);
			Transform transform = val2.transform;
			Stretch((RectTransform)(object)((transform is RectTransform) ? transform : null));
			Image component = val2.GetComponent<Image>();
			((Graphic)component).color = new Color(0f, 0f, 0f, 0.55f);
			((Graphic)component).raycastTarget = false;
			component.sprite = WhiteSprite();
			component.type = (Type)3;
			component.fillMethod = (FillMethod)4;
			component.fillOrigin = 2;
			component.fillClockwise = false;
			component.fillAmount = 0f;
			GameObject val3 = new GameObject("text", new Type[2]
			{
				typeof(RectTransform),
				typeof(Text)
			});
			val3.transform.SetParent(val.transform, false);
			Transform transform2 = val3.transform;
			Stretch((RectTransform)(object)((transform2 is RectTransform) ? transform2 : null));
			Text component2 = val3.GetComponent<Text>();
			component2.alignment = (TextAnchor)4;
			component2.fontSize = 14;
			((Graphic)component2).color = Color.white;
			((Graphic)component2).raycastTarget = false;
			component2.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			component2.text = "";
			SkyheimCooldownItem obj = val.AddComponent<SkyheimCooldownItem>();
			AccessTools.Field(typeof(SkyheimCooldownItem), "_text")?.SetValue(obj, component2);
			AccessTools.Field(typeof(SkyheimCooldownItem), "_swipe")?.SetValue(obj, component);
			return val;
		}

		private static void Stretch(RectTransform rt)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)rt))
			{
				rt.anchorMin = Vector2.zero;
				rt.anchorMax = Vector2.one;
				rt.offsetMin = Vector2.zero;
				rt.offsetMax = Vector2.zero;
				((Transform)rt).localScale = Vector3.one;
			}
		}

		private static Sprite WhiteSprite()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			Texture2D whiteTexture = Texture2D.whiteTexture;
			return Sprite.Create(whiteTexture, new Rect(0f, 0f, (float)((Texture)whiteTexture).width, (float)((Texture)whiteTexture).height), new Vector2(0.5f, 0.5f), 100f);
		}
	}
	[HarmonyPatch(typeof(SkyheimPieceData), "OnBeforeSerialize")]
	internal static class SkyheimPieceData_OnBeforeSerialize_Patch
	{
		private static readonly FieldInfo Resources = AccessTools.Field(typeof(SkyheimPieceData), "_resources");

		private static bool Prefix(SkyheimPieceData __instance)
		{
			return Resources?.GetValue(__instance) != null;
		}
	}
	internal static class HealBalance
	{
		private const float TickInterval = 1f;

		private const string RuneHealNameToken = "rune_heal";

		private static readonly int HealRuneStatusHash = StringExtensionMethods.GetStableHashCode("se_rune_heal");

		private static ConfigEntry<float> _totalMultiplier;

		private static ConfigEntry<float> _healDurationSeconds;

		private static ConfigEntry<float> _minIconSeconds;

		private static ConfigEntry<bool> _showHealVfx;

		private static readonly FieldInfo BaseHealth = AccessTools.Field(typeof(SE_Heal), "_baseHealth");

		private static readonly FieldInfo HealthPerQuality = AccessTools.Field(typeof(SE_Heal), "_healthPerQuality");

		private static readonly FieldInfo DurationPerSkill = AccessTools.Field(typeof(SE_Heal), "_durationPerSkill");

		internal static void Bind(ConfigFile config)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			_totalMultiplier = config.Bind<float>("Rune healing", "Total Heal Multiplier", 0.9f, new ConfigDescription("Fraction of Skyheim's healing rune HP. 1 = 40 HP at quality 1 before Elemental Magic skill; 0.9 is about 36 HP. Each quality adds 5 HP before this multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 2f), Array.Empty<object>()));
			_healDurationSeconds = config.Bind<float>("Rune healing", "Heal Duration Seconds", 8f, new ConfigDescription("Spread healing over this many seconds (HoT).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
			_minIconSeconds = config.Bind<float>("Rune healing", "Min Status Icon Seconds", 10f, new ConfigDescription("How long the healing status icon stays on the effect bar (allies included).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 60f), Array.Empty<object>()));
			_showHealVfx = config.Bind<bool>("Rune healing", "Show Heal Vfx On Allies", true, "Spawn a short heal burst VFX on each character when the healing rune HoT is applied. Its volume is the Audio slider for vfx_Potion_health_medium.");
		}

		internal static bool IsSkyheimHealRune(SE_Heal heal)
		{
			if ((Object)(object)heal == (Object)null)
			{
				return false;
			}
			if (((StatusEffect)heal).NameHash() == HealRuneStatusHash)
			{
				return true;
			}
			if ((((Object)heal).name ?? string.Empty).IndexOf("rune_heal", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			return (((StatusEffect)heal).m_name ?? string.Empty).IndexOf("sh_se_rune_heal", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		internal static bool TryApplyPackHeal(SE_Heal instance, int itemLevel, float skillLevel)
		{
			if ((Object)(object)instance == (Object)null || _totalMultiplier == null)
			{
				return false;
			}
			float num = ((BaseHealth?.GetValue(instance) is float num2) ? num2 : 40f);
			float num3 = ((HealthPerQuality?.GetValue(instance) is float num4) ? num4 : 5f);
			float num5 = ((DurationPerSkill?.GetValue(instance) is float num6) ? num6 : 0.01f);
			int num7 = ((itemLevel < 1) ? 1 : itemLevel);
			float num8 = 1f + num5 * skillLevel;
			float num9 = (num + num3 * (float)(num7 - 1)) * num8 * _totalMultiplier.Value;
			if (num9 <= 0f)
			{
				return false;
			}
			float num10 = Mathf.Max(1f, _healDurationSeconds.Value);
			float ttl = Mathf.Max(num10, _minIconSeconds.Value);
			int num11 = Mathf.Max(1, Mathf.CeilToInt(num10 / 1f));
			float num12 = num9 / (float)num11;
			((StatusEffect)instance).m_ttl = ttl;
			((SE_Stats)instance).m_healthOverTimeDuration = num10;
			((SE_Stats)instance).m_healthOverTimeInterval = 1f;
			((SE_Stats)instance).m_healthOverTimeTicks = num11;
			((SE_Stats)instance).m_healthOverTimeTickHP = num12;
			((SE_Stats)instance).m_healthOverTime = 0f;
			if ((Object)(object)((StatusEffect)instance).m_character != (Object)null)
			{
				HealDiagnostics.Log($"SE_Heal applied to {((StatusEffect)instance).m_character.m_name}: quality {num7}, skill {skillLevel:0.#}, total {num9:0.#} HP over {num10:0.#}s ({num11} ticks of {num12:0.##}), hp {((StatusEffect)instance).m_character.GetHealth():0}/{((StatusEffect)instance).m_character.GetMaxHealth():0}");
			}
			return true;
		}

		internal static void TryPlayHealVfx(Character character)
		{
			//IL_0065: 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)
			if (_showHealVfx == null || !_showHealVfx.Value || (Object)(object)character == (Object)null)
			{
				return;
			}
			ZNetScene instance = ZNetScene.instance;
			GameObject val = ((instance != null) ? instance.GetPrefab("vfx_Potion_health_medium") : null);
			if ((Object)(object)val == (Object)null)
			{
				ZNetScene instance2 = ZNetScene.instance;
				val = ((instance2 != null) ? instance2.GetPrefab("vfx_Heal") : null);
			}
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			SkyheimAudio.Enter();
			try
			{
				Object.Instantiate<GameObject>(val, character.GetCenterPoint(), Quaternion.identity);
			}
			finally
			{
				SkyheimAudio.Exit();
			}
		}
	}
	[HarmonyPatch(typeof(SE_Heal), "SetLevel")]
	internal static class SE_Heal_SetLevel_PackBalance_Patch
	{
		private static bool Prefix(SE_Heal __instance, int itemLevel, float skillLevel)
		{
			if ((Object)(object)__instance == (Object)null || !HealBalance.IsSkyheimHealRune(__instance))
			{
				return true;
			}
			if (!HealBalance.TryApplyPackHeal(__instance, itemLevel, skillLevel))
			{
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(SE_Heal), "Setup")]
	internal static class SE_Heal_Setup_Vfx_Patch
	{
		private static void Postfix(SE_Heal __instance, Character character)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)character == (Object)null) && HealBalance.IsSkyheimHealRune(__instance))
			{
				HealBalance.TryPlayHealVfx(character);
			}
		}
	}
	internal static class HealDiagnostics
	{
		private const string HealRunePrefab = "rune_heal";

		private const string HealAoePrefab = "rune_heal_aoe";

		private static readonly int HealStatusHash = StringExtensionMethods.GetStableHashCode("se_rune_heal");

		private static ConfigEntry<bool> _enabled;

		internal static bool Enabled
		{
			get
			{
				if (_enabled != null)
				{
					return _enabled.Value;
				}
				return false;
			}
		}

		internal static void Bind(ConfigFile config)
		{
			_enabled = config.Bind<bool>("Rune healing", "Debug Logging", false, "Log each step of a Rune of Healing cast to BepInEx/LogOutput.log. Requires a game restart to take effect.");
		}

		internal static void Log(string message)
		{
			if (Enabled)
			{
				Plugin.Log("[HealDebug] " + message);
			}
		}

		internal static void Apply(Harmony harmony, string configPath)
		{
			Plugin.Log("[HealDebug] Debug Logging is " + (Enabled ? "ON" : "OFF") + " (read from " + configPath + ").");
			if (Enabled)
			{
				TryPatch(harmony, AccessTools.Method(typeof(Humanoid), "StartAttack", (Type[])null, (Type[])null), null, "StartAttack_Postfix");
				TryPatch(harmony, AccessTools.Method(typeof(Attack), "OnAttackTrigger", (Type[])null, (Type[])null), "OnAttackTrigger_Prefix");
				TryPatch(harmony, AccessTools.Method(typeof(Aoe), "Setup", (Type[])null, (Type[])null), null, "AoeSetup_Postfix");
				TryPatch(harmony, AccessTools.Method(typeof(Character), "Damage", (Type[])null, (Type[])null), "Damage_Prefix", null, 800);
				TryPatch(harmony, AccessTools.Method(typeof(Character), "RPC_Damage", (Type[])null, (Type[])null), "RpcDamage_Prefix", null, 800);
				TryPatch(harmony, AccessTools.Method(typeof(SEMan), "AddStatusEffect", new Type[5]
				{
					typeof(int),
					typeof(bool),
					typeof(int),
					typeof(float),
					typeof(short)
				}, (Type[])null), null, "AddStatusEffect_Postfix");
			}
		}

		private static void TryPatch(Harmony harmony, MethodInfo target, string prefix = null, string postfix = null, int priority = 400)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			if (target == null)
			{
				Plugin.LogWarning("[HealDebug] Could not find a target for " + (prefix ?? postfix) + "; skipped.");
				return;
			}
			try
			{
				harmony.Patch((MethodBase)target, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(HealDiagnostics), prefix, (Type[])null)
				{
					priority = priority
				}, (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(HealDiagnostics), postfix, (Type[])null)
				{
					priority = priority
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			catch (Exception ex)
			{
				Plugin.LogWarning("[HealDebug] Failed to patch " + target.DeclaringType?.Name + "." + target.Name + ": " + ex.Message);
			}
		}

		private static bool IsHealRune(ItemData item)
		{
			if (item == null)
			{
				return false;
			}
			if ((Object)(object)item.m_dropPrefab != (Object)null)
			{
				if (((Object)item.m_dropPrefab).name.StartsWith("rune_heal", StringComparison.Ordinal))
				{
					return !((Object)item.m_dropPrefab).name.StartsWith("rune_heal_aoe", StringComparison.Ordinal);
				}
				return false;
			}
			if (item.m_shared?.m_name != null)
			{
				return item.m_shared.m_name.IndexOf("rune_heal", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		private static void StartAttack_Postfix(Humanoid __instance, bool __result)
		{
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				ItemData currentWeapon = __instance.GetCurrentWeapon();
				if (IsHealRune(currentWeapon))
				{
					float num = ((SkyheimCooldown.Instance != null) ? SkyheimCooldown.Instance.GetCooldown("rune_heal") : (-1f));
					bool flag = (Object)(object)ObjectDB.instance != (Object)null && (Object)(object)ObjectDB.instance.GetStatusEffect(HealStatusHash) != (Object)null;
					Log(string.Format("StartAttack with Rune of Healing -> {0}; se_rune_heal registered {1}; eitr {2:0.#}/{3:0.#}, cost {4:0.#}, cooldown left {5:0.#}s, godMode {6}, debugFly {7}", __result ? "started" : "REFUSED", flag, Player.m_localPlayer.GetEitr(), ((Character)Player.m_localPlayer).GetMaxEitr(), currentWeapon.m_shared.m_attack.m_attackEitr, num, ((Character)__instance).InGodMode(), ((Character)__instance).IsDebugFlying()));
				}
			}
		}

		private static void OnAttackTrigger_Prefix(Attack __instance)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance?.m_character != (Object)(object)Player.m_localPlayer) && IsHealRune(__instance.m_weapon))
			{
				Log(string.Format("Attack trigger fired (type {0}, projectile {1}).", __instance.m_attackType, ((Object)(object)__instance.m_attackProjectile != (Object)null) ? ((Object)__instance.m_attackProjectile).name : "none"));
			}
		}

		private static void AoeSetup_Postfix(Aoe __instance, Character owner, HitData hitData)
		{
			if (!((Object)(object)__instance == (Object)null) && ((Object)((Component)__instance).gameObject).name.StartsWith("rune_heal_aoe", StringComparison.Ordinal))
			{
				Log(string.Format("Heal area spawned: owner {0}, hitOwner {1}, radius {2}, status hash {3} (expected {4}), hitData {5}.", ((Object)(object)owner != (Object)null) ? owner.m_name : "none", __instance.m_hitOwner, __instance.m_radius, __instance.m_statusEffectHash, HealStatusHash, (hitData != null) ? "set" : "null"));
			}
		}

		private static void Damage_Prefix(Character __instance, HitData hit)
		{
			if (!((Object)(object)__instance == (Object)null) && hit != null && hit.m_statusEffectHash == HealStatusHash)
			{
				Log($"Heal hit sent to {__instance.m_name} (netview valid {(Object)(object)__instance.m_nview != (Object)null && __instance.m_nview.IsValid()}).");
			}
		}

		private static void AddStatusEffect_Postfix(SEMan __instance, int nameHash, StatusEffect __result)
		{
			if (nameHash == HealStatusHash)
			{
				Character val = __instance?.m_character;
				Log("AddStatusEffect se_rune_heal on " + (((Object)(object)val != (Object)null) ? val.m_name : "?") + ": " + (((Object)(object)__result != (Object)null) ? "new effect added" : "no new effect (refreshed existing, not owner, or not registered)") + ".");
			}
		}

		private static void RpcDamage_Prefix(Character __instance, HitData hit)
		{
			if (!((Object)(object)__instance == (Object)null) && hit != null && hit.m_statusEffectHash == HealStatusHash)
			{
				bool flag = (Object)(object)__instance.m_nview != (Object)null && __instance.m_nview.IsOwner();
				Log($"Heal hit reached {__instance.m_name}: owner {flag}, debugFly {__instance.IsDebugFlying()}, dead {__instance.IsDead()}, teleporting {__instance.IsTeleporting()}, hp {__instance.GetHealth():0}/{__instance.GetMaxHealth():0}, attacker set {hit.HaveAttacker()}, pvp {__instance.IsPVPEnabled()}.");
			}
		}
	}
	[HarmonyPatch]
	internal static class HealSelfFallback
	{
		private const string HealAoe = "rune_heal_aoe";

		private static readonly int HealStatusHash = StringExtensionMethods.GetStableHashCode("se_rune_heal");

		private static Aoe _checking;

		private static bool _ownerHit;

		private static bool IsHealAoe(Aoe aoe)
		{
			if ((Object)(object)aoe != (Object)null)
			{
				return ((Object)((Component)aoe).gameObject).name.StartsWith("rune_heal_aoe", StringComparison.Ordinal);
			}
			return false;
		}

		[HarmonyPatch(typeof(Aoe), "CheckHits")]
		[HarmonyPrefix]
		private static void CheckHits_Prefix(Aoe __instance)
		{
			_checking = (IsHealAoe(__instance) ? __instance : null);
			_ownerHit = false;
		}

		[HarmonyPatch(typeof(Character), "Damage")]
		[HarmonyPrefix]
		[HarmonyPriority(800)]
		private static void Damage_Prefix(Character __instance, HitData hit)
		{
			if ((Object)(object)_checking != (Object)null && hit != null && (Object)(object)__instance == (Object)(object)_checking.m_owner && hit.m_statusEffectHash == HealStatusHash)
			{
				_ownerHit = true;
			}
		}

		[HarmonyPatch(typeof(Aoe), "CheckHits")]
		[HarmonyFinalizer]
		private static void CheckHits_Finalizer(Aoe __instance)
		{
			//IL_008b: 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_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Invalid comparison between Unknown and I4
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			Aoe checking = _checking;
			bool ownerHit = _ownerHit;
			_checking = null;
			_ownerHit = false;
			if ((Object)(object)checking == (Object)null || (Object)(object)checking != (Object)(object)__instance || ownerHit || !checking.m_hitOwner)
			{
				return;
			}
			Character owner = checking.m_owner;
			Player val = (Player)(object)((owner is Player) ? owner : null);
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && !((Character)val).IsDead() && !((Character)val).IsDebugFlying())
			{
				int num = ((checking.m_statusEffectHash != 0) ? checking.m_statusEffectHash : HealStatusHash);
				if (num == HealStatusHash && !(Vector3.Distance(((Character)val).GetCenterPoint(), ((Component)checking).transform.position) > checking.m_radius + 2f))
				{
					float num2 = (((int)checking.m_skill != 0 && (int)checking.m_skill != 999) ? ((Character)val).GetSkillLevel(checking.m_skill) : 0f);
					SEMan sEMan = ((Character)val).GetSEMan();
					sEMan.RemoveStatusEffect(num, true);
					sEMan.AddStatusEffect(num, true, checking.m_level, num2, (short)(-1));
					HealDiagnostics.Log($"Heal area missed the caster; applied se_rune_heal directly (quality {checking.m_level}, skill {num2:0.#}).");
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class ImmolateAuraGuard
	{
		private const string AoePrefabName = "rune_immolate_aoe";

		private static ConfigEntry<bool> _blockShockingCharge;

		private static ConfigEntry<float> _volumeScale;

		private static ConfigEntry<bool> _oneSoundPerTick;

		private static Aoe _currentAoe;

		private static readonly Dictionary<int, float> LastSoundTime = new Dictionary<int, float>();

		internal static bool InImmolateHit => (Object)(object)_currentAoe != (Object)null;

		internal static void Bind(ConfigFile config)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			_blockShockingCharge = config.Bind<bool>("Epic Loot compat", "Block Shocking Charge From Immolation Aura", true, "When true, hits from the Immolation aura do not build or discharge Epic Loot Eikthyr Shocking Charge.");
			_volumeScale = config.Bind<float>("Rune immolation", "Aura Audio Volume Scale", 0.05f, new ConfigDescription("Unused. Immolation hit volume is the Audio slider for that sound. Left so older configs still load.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			_oneSoundPerTick = config.Bind<bool>("Rune immolation", "One Hit Sound Per Tick", true, "When true, an aura tick that hits several enemies plays the explosion sound once instead of once per enemy.");
		}

		internal static void Apply(Harmony harmony)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			if (_blockShockingCharge != null && _blockShockingCharge.Value)
			{
				Type type = AccessTools.TypeByName("EpicLoot.MagicItemEffects.Shards.EikthyrShockingCharge");
				MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, "OnDamageDealt", (Type[])null, (Type[])null) : null);
				if (!(methodInfo == null))
				{
					harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ImmolateAuraGuard), "ShockingCharge_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					Plugin.Log("Epic Loot: Immolation aura hits will not trigger Eikthyr Shocking Charge.");
				}
			}
		}

		private static bool IsImmolateAoe(Aoe aoe)
		{
			if ((Object)(object)aoe != (Object)null)
			{
				return ((Object)((Component)aoe).gameObject).name.StartsWith("rune_immolate_aoe", StringComparison.Ordinal);
			}
			return false;
		}

		[HarmonyPatch(typeof(Aoe), "OnHit")]
		[HarmonyPrefix]
		private static void OnHit_Prefix(Aoe __instance)
		{
			_currentAoe = (IsImmolateAoe(__instance) ? __instance : null);
		}

		[HarmonyPatch(typeof(Aoe), "OnHit")]
		[HarmonyFinalizer]
		private static void OnHit_Finalizer()
		{
			_currentAoe = null;
		}

		[HarmonyPatch(typeof(EffectList), "Create")]
		[HarmonyPostfix]
		private static void EffectList_Create_Postfix(EffectList __instance, GameObject[] __result)
		{
			if ((Object)(object)_currentAoe == (Object)null || __result == null || _volumeScale == null || __instance != _currentAoe.m_hitEffects || _volumeScale == null || !_oneSoundPerTick.Value || ClaimTickSound(_currentAoe))
			{
				return;
			}
			foreach (GameObject val in __result)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				ZSFX[] componentsInChildren = val.GetComponentsInChildren<ZSFX>(true);
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					AudioSource component = ((Component)componentsInChildren[j]).GetComponent<AudioSource>();
					if ((Object)(object)component != (Object)null)
					{
						component.mute = true;
					}
				}
			}
		}

		private static bool ClaimTickSound(Aoe aoe)
		{
			int instanceID = ((Object)aoe).GetInstanceID();
			float time = Time.time;
			float num = Mathf.Max(0.25f, aoe.m_hitInterval * 0.5f);
			if (LastSoundTime.TryGetValue(instanceID, out var value) && time - value < num)
			{
				return false;
			}
			if (LastSoundTime.Count > 64)
			{
				LastSoundTime.Clear();
			}
			LastSoundTime[instanceID] = time;
			return true;
		}

		private static bool ShockingCharge_Prefix()
		{
			return !InImmolateHit;
		}
	}
	internal static class MagicSkillBalance
	{
		private static readonly SkillType[] MagicSkills;

		private static ConfigEntry<float> _gain;

		private static ConfigEntry<int> _loss;

		internal static void Bind(ConfigFile config)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			_gain = config.Bind<float>("Magic skills", "Skill Experience Gain Factor", 1f, new ConfigDescription("Factor for experience gained for the rune magic skills.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 5f), Array.Empty<object>()));
			_loss = config.Bind<int>("Magic skills", "Skill Experience Loss", 0, new ConfigDescription("How much experience to lose in the rune magic skills on death.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
		}

		private static bool IsMagic(SkillType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Expected I4, but got Unknown
			int num = (int)type;
			if (num >= 200)
			{
				return num <= 203;
			}
			return false;
		}

		[HarmonyPatch(typeof(Skills), "GetSkillDef")]
		[HarmonyPriority(0)]
		[HarmonyPostfix]
		private static void GetSkillDef_Postfix(SkillType type, SkillDef __result)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			if (__result != null && IsMagic(type) && _gain != null)
			{
				__result.m_increseStep = _gain.Value;
			}
		}

		[HarmonyPatch(typeof(Skills), "OnDeath")]
		[HarmonyPriority(800)]
		[HarmonyPrefix]
		private static void OnDeath_Prefix(Skills __instance, ref Dictionary<SkillType, Skill> __state)
		{
			//IL_002a: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			__state = new Dictionary<SkillType, Skill>();
			if (__instance?.m_skillData == null || _loss == null)
			{
				return;
			}
			SkillType[] magicSkills = MagicSkills;
			foreach (SkillType key in magicSkills)
			{
				if (__instance.m_skillData.TryGetValue(key, out var value))
				{
					__state[key] = value;
					if (_loss.Value > 0)
					{
						Skill obj = value;
						obj.m_level -= value.m_level * (float)_loss.Value / 100f;
						value.m_accumulator = 0f;
					}
					__instance.m_skillData.Remove(key);
				}
			}
		}

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

		static MagicSkillBalance()
		{
			SkillType[] array = new SkillType[4];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			MagicSkills = (SkillType[])(object)array;
		}
	}
	[BepInPlugin("cjayride.skyheimcompat", "Cjayride Skyheim Compat", "1.1.29")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGUID = "cjayride.skyheimcompat";

		public const string PluginName = "Cjayride Skyheim Compat";

		public const string PluginVersion = "1.1.29";

		internal const string SenealGuid = "seneaL.valheim.ui";

		internal static Plugin Instance;

		private Harmony _harmony;

		private static MethodInfo _addWord;

		private static bool _applying;

		private static bool _loggedSuccess;

		private static bool _languageApplied;

		private void Awake()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			Instance = this;
			WarnIfUnfixedSkyheim();
			_harmony = new Harmony("cjayride.skyheimcompat");
			RemoveSkyheimInventoryTooltipPrefix();
			RemoveSkyheimHudPrefabPatches();
			UnpatchByDeclaringType(typeof(InventoryGui), "UpdateContainer", (HarmonyPatchType)1, "SkyheimAltarPanel");
			WindfuryDamageGuard.RemoveOriginal(_harmony);
			AltarPanelFix.Apply(_harmony);
			CooldownPrefabFix.Replace();
			MagicSkillBalance.Bind(((BaseUnityPlugin)this).Config);
			HealBalance.Bind(((BaseUnityPlugin)this).Config);
			RuneAuraRadius.Bind(((BaseUnityPlugin)this).Config);
			HealDiagnostics.Bind(((BaseUnityPlugin)this).Config);
			AltarImbueCompat.Bind(((BaseUnityPlugin)this).Config);
			AltarCostHint.ApplySeneal(_harmony);
			ImmolateAuraGuard.Bind(((BaseUnityPlugin)this).Config);
			SkyheimAudio.Bind(((BaseUnityPlugin)this).Config);
			_harmony.PatchAll();
			SkyheimAudio.Apply(_harmony);
			ImmolateAuraGuard.Apply(_harmony);
			HealDiagnostics.Apply(_harmony, ((BaseUnityPlugin)this).Config.ConfigFilePath);
			SenealCooldownOverlay.Init(_harmony);
			ApplySkyheimLocalization();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Cjayride Skyheim Compat 1.1.29 loaded.");
		}

		internal static void Log(string message)
		{
			Plugin instance = Instance;
			if (instance != null)
			{
				((BaseUnityPlugin)instance).Logger.LogInfo((object)message);
			}
		}

		internal static void LogWarning(string message)
		{
			Plugin instance = Instance;
			if (instance != null)
			{
				((BaseUnityPlugin)instance).Logger.LogWarning((object)message);
			}
		}

		private void WarnIfUnfixedSkyheim()
		{
			try
			{
				Type type = AccessTools.TypeByName("SkyheimAltarPanel");
				if (type == null)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)"SkyheimAltarPanel was not found. Uninstall makail-Skyheim. Install cjayride-SkyheimFix (rewritten skyheim.dll) together with this Compat package. Compat cannot load runes if the original 1.3.12 DLL is present.");
					return;
				}
				FieldInfo fieldInfo = AccessTools.Field(type, "_leftSlot");
				if (!(fieldInfo == null))
				{
					string text = fieldInfo.FieldType?.Name;
					if (!(text == "InventoryElement"))
					{
						((BaseUnityPlugin)this).Logger.LogError((object)("SkyheimAltarPanel._leftSlot is " + text + ", not InventoryElement. Uninstall makail-Skyheim. Install cjayride-SkyheimFix (rewritten skyheim.dll) together with this Compat package. Compat cannot load runes if the original 1.3.12 DLL is present."));
					}
				}
			}
			catch (TypeLoadException ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Skyheim failed to load (InventoryGrid.Element was removed in Valheim 1.0). Uninstall makail-Skyheim. Install cjayride-SkyheimFix (rewritten skyheim.dll) together with this Compat package. Compat cannot load runes if the original 1.3.12 DLL is present.");
				((BaseUnityPlugin)this).Logger.LogError((object)ex.ToString());
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Skyheim failed to load. Uninstall makail-Skyheim. Install cjayride-SkyheimFix (rewritten skyheim.dll) together with this Compat package. Compat cannot load runes if the original 1.3.12 DLL is present.");
				((BaseUnityPlugin)this).Logger.LogError((object)ex2.ToString());
			}
		}

		internal static bool SenealUiLoaded()
		{
			if (Chainloader.PluginInfos != null)
			{
				return Chainloader.PluginInfos.ContainsKey("seneaL.valheim.ui");
			}
			return false;
		}

		private static void RemoveSkyheimHudPrefabPatches()
		{
			if (SenealUiLoaded())
			{
				UnpatchByDeclaringType(typeof(Hud), "Awake", (HarmonyPatchType)2, "SkyheimCooldown");
				UnpatchByDeclaringType(typeof(InventoryGui), "Awake", (HarmonyPatchType)2, "SkyheimCooldown");
			}
		}

		private static void UnpatchByDeclaringType(Type originalType, string methodName, HarmonyPatchType kind, string declaringTypeName)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			MethodInfo methodInfo = AccessTools.DeclaredMethod(originalType, methodName, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				return;
			}
			Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
			if (patchInfo == null)
			{
				return;
			}
			foreach (Patch item in (IEnumerable<Patch>)(((int)kind == 1) ? patchInfo.Prefixes : patchInfo.Postfixes))
			{
				if (!(item.PatchMethod?.DeclaringType?.Name != declaringTypeName))
				{
					new Harmony(item.owner).Unpatch((MethodBase)methodInfo, item.PatchMethod);
					Plugin instance = Instance;
					if (instance != null)
					{
						((BaseUnityPlugin)instance).Logger.LogInfo((object)("Removed Skyheim " + declaringTypeName + " " + originalType.Name + "." + methodName + " so SeneaL UI can own the HUD."));
					}
				}
			}
		}

		private static void RemoveSkyheimInventoryTooltipPrefix()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(InventoryGrid), "CreateItemTooltip", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				return;
			}
			Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
			if (patchInfo == null)
			{
				return;
			}
			foreach (Patch prefix in patchInfo.Prefixes)
			{
				if (!(prefix.PatchMethod?.DeclaringType?.Name != "SkyheimArmor"))
				{
					new Harmony(prefix.owner).Unpatch((MethodBase)methodInfo, prefix.PatchMethod);
					Plugin instance = Instance;
					if (instance != null)
					{
						((BaseUnityPlugin)instance).Logger.LogInfo((object)"Removed Skyheim CreateItemTooltip prefix so vanilla inventory tooltips run.");
					}
				}
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		internal static bool IsBlockedByCooldown(Humanoid character, ItemData weapon)
		{
			if ((Object)(object)character == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)character != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			if (SkyheimCooldown.Instance == null)
			{
				return false;
			}
			SkyheimItemData runeData = GetRuneData(weapon);
			if ((Object)(object)runeData == (Object)null || runeData.Cooldown <= 0f)
			{
				return false;
			}
			return SkyheimCooldown.Instance.GetCooldown(((Object)((Component)runeData).gameObject).name) > 0f;
		}

		internal static void ApplySkyheimLocalization(string languageName = null)
		{
			bool flag = !string.IsNullOrEmpty(languageName);
			if ((!flag && _languageApplied) || _applying || Localization.instance == null)
			{
				return;
			}
			_applying = true;
			try
			{
				JSONNode val = JSON.Parse(ReadLocalizationJson());
				string text = (flag ? languageName : "English");
				JSONNode val2 = val[text] ?? val["English"];
				if (val2 == (object)null || val2.Count == 0)
				{
					Plugin instance = Instance;
					if (instance != null)
					{
						((BaseUnityPlugin)instance).Logger.LogWarning((object)"Skyheim localization JSON had no usable language block.");
					}
					return;
				}
				if (_addWord == null)
				{
					_addWord = typeof(Localization).GetMethod("AddWord", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if (_addWord == null)
				{
					Plugin instance2 = Instance;
					if (instance2 != null)
					{
						((BaseUnityPlugin)instance2).Logger.LogWarning((object)"Localization.AddWord was not found.");
					}
					return;
				}
				int num = 0;
				foreach (KeyValuePair<string, JSONNode> item in val2.Linq)
				{
					_addWord.Invoke(Localization.instance, new object[2]
					{
						item.Key,
						JSONNode.op_Implicit(item.Value)
					});
					num++;
				}
				_languageApplied = true;
				if (!_loggedSuccess)
				{
					_loggedSuccess = true;
					Plugin instance3 = Instance;
					if (instance3 != null)
					{
						((BaseUnityPlugin)instance3).Logger.LogInfo((object)$"Applied {num} Skyheim localization entries ({text}).");
					}
				}
			}
			catch (Exception arg)
			{
				Plugin instance4 = Instance;
				if (instance4 != null)
				{
					((BaseUnityPlugin)instance4).Logger.LogError((object)$"Skyheim localization load failed: {arg}");
				}
			}
			finally
			{
				_applying = false;
			}
		}

		private static string ReadLocalizationJson()
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string text = Array.Find(executingAssembly.GetManifestResourceNames(), (string name) => name.EndsWith("skyheim.json", StringComparison.OrdinalIgnoreCase));
			if (!string.IsNullOrEmpty(text))
			{
				using (Stream stream = executingAssembly.GetManifestResourceStream(text))
				{
					using StreamReader streamReader = new StreamReader(stream);
					return streamReader.ReadToEnd();
				}
			}
			string path = Path.Combine(Path.GetDirectoryName(typeof(SkyheimPlugin).Assembly.Location) ?? string.Empty, "skyheim.json");
			if (File.Exists(path))
			{
				return File.ReadAllText(path);
			}
			throw new FileNotFoundException("Embedded skyheim.json was missing and no loose skyheim.json was found next to skyheim.dll.");
		}

		private static SkyheimItemData GetRuneData(ItemData item)
		{
			if (item == null)
			{
				return null;
			}
			GameObject val = item.m_dropPrefab;
			if ((Object)(object)val == (Object)null && (Object)(object)ObjectDB.instance != (Object)null && item.m_shared != null)
			{
				val = ObjectDB.instance.GetItemPrefab(item.m_shared.m_name);
			}
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.GetComponent<SkyheimItemData>();
		}
	}
	[HarmonyPatch(typeof(SkyheimAttackRecall), "OnAttackTrigger")]
	internal static class SkyheimAttackRecall_OnAttackTrigger_Patch
	{
		private static bool Prefix(ref bool __result)
		{
			if ((Object)(object)Game.instance != (Object)null)
			{
				Game.instance.RequestRespawn(1.25f, true);
			}
			__result = true;
			return false;
		}
	}
	[HarmonyPatch(typeof(Localization), "SetLanguage")]
	internal static class Localization_SetLanguage_Patch
	{
		private static void Postfix(string language)
		{
			Plugin.ApplySkyheimLocalization(language);
		}
	}
	[HarmonyPatch(typeof(SkyheimItemData), "Awake")]
	internal static class SkyheimItemData_Awake_Patch
	{
		private static void Prefix()
		{
			Plugin.ApplySkyheimLocalization();
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	[HarmonyPriority(800)]
	internal static class ObjectDB_Awake_Patch
	{
		private static void Prefix()
		{
			Plugin.ApplySkyheimLocalization();
		}
	}
	[HarmonyPatch(typeof(Player), "GetCurrentCraftingStation")]
	internal static class Player_GetCurrentCraftingStation_Patch
	{
		private static void Postfix(ref CraftingStation __result)
		{
			if (!Object.op_Implicit((Object)(object)__result))
			{
				__result = null;
			}
		}
	}
	[HarmonyPatch(typeof(Humanoid), "StartAttack")]
	[HarmonyPriority(800)]
	internal static class Humanoid_StartAttack_Patch
	{
		private static bool Prefix(Humanoid __instance, ref bool __result)
		{
			if (!Plugin.IsBlockedByCooldown(__instance, __instance.GetCurrentWeapon()))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Attack), "Start")]
	[HarmonyPriority(800)]
	internal static class Attack_Start_Patch
	{
		private static bool Prefix(Humanoid character, ItemData weapon, ref bool __result)
		{
			if (!Plugin.IsBlockedByCooldown(character, weapon))
			{
				return true;
			}
			__result = false;
			return false;
		}
	}
	[HarmonyPatch(typeof(Attack), "StartWithoutAnimation")]
	[HarmonyPriority(800)]
	internal static class Attack_StartWithoutAnimation_Patch
	{
		private static bool Prefix(Humanoid character, ItemData weapon)
		{
			return !Plugin.IsBlockedByCooldown(character, weapon);
		}
	}
	[HarmonyPatch(typeof(InventoryGui), "Awake")]
	[HarmonyPriority(0)]
	internal static class InventoryGui_Awake_TooltipPrefab_Patch
	{
		private static void Postfix(InventoryGui __instance)
		{
			if (!Plugin.SenealUiLoaded())
			{
				RestoreTooltipPrefabText(__instance.m_playerGrid);
				RestoreTooltipPrefabText(__instance.m_containerGrid);
				TryInjectInventoryCooldown(__instance);
			}
		}

		private static void TryInjectInventoryCooldown(InventoryGui gui)
		{
			try
			{
				if (!Object.op_Implicit((Object)(object)gui) || !Object.op_Implicit((Object)(object)gui.m_playerGrid) || !Object.op_Implicit((Object)(object)gui.m_playerGrid.m_elementPrefab) || SkyheimCooldown.Instance == null)
				{
					return;
				}
				object? obj = AccessTools.Field(typeof(SkyheimCooldown), "_cooldownPrefab")?.GetValue(SkyheimCooldown.Instance);
				GameObject val = (GameObject)((obj is GameObject) ? obj : null);
				if (Object.op_Implicit((Object)(object)val))
				{
					GameObject elementPrefab = gui.m_playerGrid.m_elementPrefab;
					if (!((Object)(object)elementPrefab.GetComponentInChildren<SkyheimCooldownItem>(true) != (Object)null))
					{
						GameObject val2 = Object.Instantiate<GameObject>(elementPrefab);
						Object.Instantiate<GameObject>(val, val2.transform);
						gui.m_playerGrid.m_elementPrefab = val2;
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.LogWarning("Skipped Skyheim inventory cooldown overlay: " + ex.Message);
			}
		}

		private static void RestoreTooltipPrefabText(InventoryGrid grid)
		{
			if (Object.op_Implicit((Object)(object)grid) && Object.op_Implicit((Object)(object)grid.m_elementPrefab))
			{
				UITooltip component = grid.m_elementPrefab.GetComponent<UITooltip>();
				if ((Object)(object)component != (Object)null && component.m_text == "")
				{
					component.m_text = null;
				}
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "CreateItemTooltip")]
	internal static class InventoryGrid_CreateItemTooltip_Patch
	{
		private static bool _settingTooltip;

		private static bool Prefix(InventoryGrid __instance, ItemData item, UITooltip tooltip)
		{
			if (!TryGetCustomName(item, out var _))
			{
				return true;
			}
			SetTooltip(__instance, item, tooltip);
			return false;
		}

		internal static void SetTooltip(InventoryGrid grid, ItemData item, UITooltip tooltip)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			if (_settingTooltip || (Object)(object)grid == (Object)null || item?.m_shared == null || (Object)(object)tooltip == (Object)null)
			{
				return;
			}
			string customName;
			string text = (TryGetCustomName(item, out customName) ? customName : item.m_shared.m_name);
			_settingTooltip = true;
			try
			{
				tooltip.Set(text, item.GetTooltip(-1), grid.m_tooltipAnchor, Vector2.zero);
			}
			finally
			{
				_settingTooltip = false;
			}
		}

		private static bool TryGetCustomName(ItemData item, out string customName)
		{
			customName = null;
			if (item?.m_customData != null && item.m_customData.TryGetValue("sh_mod_name", out customName))
			{
				return !string.IsNullOrEmpty(customName);
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(UITooltip), "OnHoverStart")]
	[HarmonyPriority(800)]
	internal static class UITooltip_OnHoverStart_Patch
	{
		private static void Prefix(UITooltip __instance)
		{
			//IL_0031: 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)
			InventoryElement component = ((Component)__instance).GetComponent<InventoryElement>();
			if ((Object)(object)component == (Object)null)
			{
				return;
			}
			InventoryGrid componentInParent = ((Component)component).GetComponentInParent<InventoryGrid>();
			if (!((Object)(object)componentInParent == (Object)null) && componentInParent.m_inventory != null)
			{
				ItemData itemAt = componentInParent.m_inventory.GetItemAt(component.Position.x, component.Position.y);
				if (itemAt != null)
				{
					InventoryGrid_CreateItemTooltip_Patch.SetTooltip(componentInParent, itemAt, __instance);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class Attack_SkyheimEitrSpend_Patch
	{
		private static readonly HashSet<Attack> Prepaid = new HashSet<Attack>();

		private static readonly Dictionary<Attack, float> HiddenCost = new Dictionary<Attack, float>();

		[HarmonyPatch(typeof(Attack), "Start")]
		[HarmonyPostfix]
		private static void Start_Postfix(Attack __instance, ref bool __result)
		{
			if (__result && !((Object)(object)__instance?.m_character == (Object)null) && __instance.m_weapon != null && !((Object)(object)__instance.m_weapon.m_dropPrefab == (Object)null) && !((Object)(object)__instance.m_weapon.m_dropPrefab.GetComponent<SkyheimItemData>() == (Object)null))
			{
				float attackEitr = __instance.GetAttackEitr((Character)(object)__instance.m_character, __instance.m_weapon);
				if (!(attackEitr <= 0f))
				{
					((Character)__instance.m_character).UseEitr(attackEitr);
					Prepaid.Add(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Attack), "Update")]
		[HarmonyPrefix]
		private static void Update_Prefix(Attack __instance)
		{
			if (Prepaid.Contains(__instance))
			{
				if (__instance.m_wasInAttack || __instance.m_attackDone)
				{
					Prepaid.Remove(__instance);
					return;
				}
				HiddenCost[__instance] = __instance.m_attackEitr;
				__instance.m_attackEitr = 0f;
			}
		}

		[HarmonyPatch(typeof(Attack), "Update")]
		[HarmonyPostfix]
		private static void Update_Postfix(Attack __instance)
		{
			if (HiddenCost.TryGetValue(__instance, out var value))
			{
				__instance.m_attackEitr = value;
				HiddenCost.Remove(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(Attack), "HaveAmmo")]
	[HarmonyPriority(0)]
	internal static class Attack_HaveAmmo_Patch
	{
		private static void Postfix(Humanoid character, ItemData weapon, ref bool __result)
		{
			if (__result && Plugin.IsBlockedByCooldown(character, weapon))
			{
				__result = false;
			}
		}
	}
	internal static class RuneAuraRadius
	{
		[HarmonyPatch(typeof(Aoe), "Setup")]
		private static class Aoe_Setup_Radius_Patch
		{
			private static void Postfix(Aoe __instance)
			{
				if (!((Object)(object)__instance == (Object)null))
				{
					string name = ((Object)((Component)__instance).gameObject).name;
					if (name.StartsWith("rune_heal_aoe", StringComparison.Ordinal) && _healRadius != null)
					{
						__instance.m_radius = _healRadius.Value;
					}
					else if (name.StartsWith("rune_warmth_aoe", StringComparison.Ordinal) && _warmthRadius != null)
					{
						__instance.m_radius = _warmthRadius.Value;
					}
				}
			}
		}

		private const string HealAoe = "rune_heal_aoe";

		private const string WarmthAoe = "rune_warmth_aoe";

		private static ConfigEntry<float> _healRadius;

		private static ConfigEntry<float> _warmthRadius;

		internal static void Bind(ConfigFile config)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			_healRadius = config.Bind<float>("Rune healing", "Heal Radius", 5f, new ConfigDescription("Meters the Rune of Healing reaches around the caster. Skyheim's prefab is 5.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
			_warmthRadius = config.Bind<float>("Rune warmth", "Warmth Radius", 30f, new ConfigDescription("Meters the Rune of Warmth reaches around the caster. Skyheim's prefab is 30, and it is an area by design.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 50f), Array.Empty<object>()));
		}
	}
	internal static class RuneConfig
	{
		private sealed class RuneBindings
		{
			public ConfigEntry<bool> Enabled;

			public ConfigEntry<float> Cooldown;

			public ConfigEntry<float> ManaDrain;

			public ConfigEntry<float> AttackEitr;

			public ConfigEntry<float> AttackStamina;

			public ConfigEntry<float> AttackRange;

			public ConfigEntry<float> DamageBlunt;

			public ConfigEntry<float> DamageSlash;

			public ConfigEntry<float> DamagePierce;

			public ConfigEntry<float> DamageFire;

			public ConfigEntry<float> DamageFrost;

			public ConfigEntry<float> DamageLightning;

			public ConfigEntry<float> DamagePoison;

			public ConfigEntry<float> DamageSpirit;

			public ConfigEntry<float> DamageChop;
		}

		private static readonly Dictionary<string, RuneBindings> Bindings = new Dictionary<string, RuneBindings>(StringComparer.OrdinalIgnoreCase);

		private static bool _bound;

		internal static void DiscoverAndApply()
		{
			if (AssetManager.AssetBundleObjects == null || AssetManager.AssetBundleObjects.Length == 0)
			{
				return;
			}
			ConfigFile config = ((BaseUnityPlugin)Plugin.Instance).Config;
			int num = 0;
			foreach (SkyheimItemData gameObject in AssetManager.GetGameObjects<SkyheimItemData>())
			{
				ItemDrop component = ((Component)gameObject).GetComponent<ItemDrop>();
				if ((Object)(object)component == (Object)null || component.m_itemData?.m_shared == null)
				{
					continue;
				}
				string name = ((Object)((Component)gameObject).gameObject).name;
				if (!Bindings.TryGetValue(name, out var value))
				{
					value = BindRune(config, name, gameObject, component);
					value.Enabled.SettingChanged += delegate
					{
						ApplyAll();
					};
					value.Cooldown.SettingChanged += delegate
					{
						ApplyAll();
					};
					value.ManaDrain.SettingChanged += delegate
					{
						ApplyAll();
					};
					value.AttackEitr.SettingChanged += delegate
					{
						ApplyAll();
					};
					value.AttackStamina.SettingChanged += delegate
					{
						ApplyAll();
					};
					value.DamageBlunt.SettingChanged += delegate
					{
						ApplyAll();
					};
					value.DamageSlash.SettingChanged += delegate
					{
						ApplyAll();
					};
					value.DamagePierce.SettingChanged += delegate
					{
						ApplyAll();
					};
					value.DamageFire.SettingChanged += delegate
					{
						ApplyAll();
					};
					value.DamageFrost.SettingChanged += delegate
					{
						ApplyAll();
					};
					value.DamageLightning.SettingChanged += delegate
					{
						ApplyAll();
					};
					value.DamagePoison.SettingChanged += delegate
					{
						ApplyAll();
					};
					value.DamageSpirit.SettingChanged += delegate
					{
						ApplyAll();
					};
					value.DamageChop.SettingChanged += delegate
					{
						ApplyAll();
					};
					value.AttackRange.SettingChanged += delegate
					{
						ApplyAll();
					};
					Bindings[name] = value;
				}
				Apply(value, gameObject, component);
				num++;
			}
			if (!_bound && num > 0)
			{
				_bound = true;
				Plugin.Log(string.Format("Skyheim rune config ready for {0} runes -> BepInEx/config/{1}.cfg", num, "cjayride.skyheimcompat"));
			}
		}

		private static RuneBindings BindRune(ConfigFile config, string section, SkyheimItemData rune, ItemDrop itemDrop)
		{
			//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_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			SharedData shared = itemDrop.m_itemData.m_shared;
			Attack attack = shared.m_attack;
			DamageTypes damages = shared.m_damages;
			string text = ((Localization.instance != null) ? Localization.instance.Localize(shared.m_name) : section);
			RuneBindings runeBindings = new RuneBindings();
			runeBindings.Enabled = config.Bind<bool>(section, "Enabled", true, "Show/craft " + text + " (" + section + ").");
			runeBindings.Cooldown = config.Bind<float>(section, "Cooldown", rune.Cooldown, "Cooldown in seconds for " + text + ".");
			runeBindings.ManaDrain = config.Bind<float>(section, "EitrDrainWhileHeld", rune.ManaDrain, "Eitr drained per second while " + text + " is held.");
			runeBindings.AttackEitr = config.Bind<float>(section, "AttackEitr", attack?.m_attackEitr ?? 0f, "Eitr cost to cast " + text + ".");
			runeBindings.AttackStamina = config.Bind<float>(section, "AttackStamina", attack?.m_attackStamina ?? 0f, "Stamina cost to cast " + text + ".");
			runeBindings.AttackRange = config.Bind<float>(section, "AttackRange", attack?.m_attackRange ?? 0f, "Attack/projectile range for " + text + ".");
			runeBindings.DamageBlunt = config.Bind<float>(section, "DamageBlunt", damages.m_blunt, "");
			runeBindings.DamageSlash = config.Bind<float>(section, "DamageSlash", damages.m_slash, "");
			runeBindings.DamagePierce = config.Bind<float>(section, "DamagePierce", damages.m_pierce, "");
			runeBindings.DamageFire = config.Bind<float>(section, "DamageFire", damages.m_fire, "");
			runeBindings.DamageFrost = config.Bind<float>(section, "DamageFrost", damages.m_frost, "");
			runeBindings.DamageLightning = config.Bind<float>(section, "DamageLightning", damages.m_lightning, "");
			runeBindings.DamagePoison = config.Bind<float>(section, "DamagePoison", damages.m_poison, "");
			runeBindings.DamageSpirit = config.Bind<float>(section, "DamageSpirit", damages.m_spirit, "");
			runeBindings.DamageChop = config.Bind<float>(section, "DamageChop", damages.m_chop, "");
			return runeBindings;
		}

		private static void ApplyAll()
		{
			foreach (SkyheimItemData gameObject in AssetManager.GetGameObjects<SkyheimItemData>())
			{
				if (Bindings.TryGetValue(((Object)((Component)gameObject).gameObject).name, out var value))
				{
					ItemDrop component = ((Component)gameObject).GetComponent<ItemDrop>();
					if ((Object)(object)component != (Object)null)
					{
						Apply(value, gameObject, component);
					}
				}
			}
		}

		private static void Apply(RuneBindings bind, SkyheimItemData rune, ItemDrop itemDrop)
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			rune.Cooldown = bind.Cooldown.Value;
			rune.ManaDrain = bind.ManaDrain.Value;
			SharedData shared = itemDrop.m_itemData.m_shared;
			if (shared.m_attack != null)
			{
				shared.m_attack.m_attackEitr = bind.AttackEitr.Value;
				shared.m_attack.m_attackStamina = bind.AttackStamina.Value;
				shared.m_attack.m_attackRange = bind.AttackRange.Value;
			}
			DamageTypes damages = shared.m_damages;
			damages.m_blunt = bind.DamageBlunt.Value;
			damages.m_slash = bind.DamageSlash.Value;
			damages.m_pierce = bind.DamagePierce.Value;
			damages.m_fire = bind.DamageFire.Value;
			damages.m_frost = bind.DamageFrost.Value;
			damages.m_lightning = bind.DamageLightning.Value;
			damages.m_poison = bind.DamagePoison.Value;
			damages.m_spirit = bind.DamageSpirit.Value;
			damages.m_chop = bind.DamageChop.Value;
			shared.m_damages = damages;
			if (ObjectDB.instance?.m_recipes == null)
			{
				return;
			}
			foreach (Recipe recipe in ObjectDB.instance.m_recipes)
			{
				if ((Object)(object)recipe != (Object)null && (Object)(object)recipe.m_item == (Object)(object)itemDrop)
				{
					recipe.m_enabled = bind.Enabled.Value;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	[HarmonyPriority(0)]
	internal static class ObjectDB_Awake_RuneConfig_Patch
	{
		private static void Postfix()
		{
			RuneConfig.DiscoverAndApply();
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	[HarmonyPriority(0)]
	internal static class ZNetScene_Awake_RuneConfig_Patch
	{
		private static void Postfix()
		{
			RuneConfig.DiscoverAndApply();
		}
	}
	internal static class SenealCooldownOverlay
	{
		private static FieldInfo _hotbarSlots;

		private static FieldInfo _hotbarActions;

		private static FieldInfo _slotRoot;

		private static MethodInfo _actionRow;

		private static bool _loggedHotbar;

		private static bool _loggedMissing;

		internal static void Init(Harmony harmony)
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Expected O, but got Unknown
			if (!Plugin.SenealUiLoaded())
			{
				return;
			}
			Type type = AccessTools.TypeByName("SeneaLUI.Hud.HotbarView");
			Type type2 = AccessTools.TypeByName("SeneaLUI.Components.Slot");
			Type type3 = AccessTools.TypeByName("SeneaLUI.Inv.Slots");
			if (type == null || type2 == null)
			{
				Plugin.LogWarning("SeneaL UI types were not found; rune cooldown overlay on the custom HUD is unavailable.");
				return;
			}
			_hotbarSlots = AccessTools.Field(type, "_slots");
			_hotbarActions = AccessTools.Field(type, "_act");
			_slotRoot = AccessTools.Field(type2, "Root");
			_actionRow = AccessTools.Method(type3, "ActionRow", new Type[1] { typeof(Inventory) }, (Type[])null);
			MethodInfo methodInfo = AccessTools.Method(type, "Tick", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(SenealCooldownOverlay), "HotbarTick_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void HotbarTick_Postfix(object __instance)
		{
			try
			{
				Player localPlayer = Player.m_localPlayer;
				Inventory val = (((Object)(object)localPlayer != (Object)null) ? ((Humanoid)localPlayer).GetInventory() : null);
				if (val == null || __instance == null)
				{
					return;
				}
				AttachSlotArray(_hotbarSlots?.GetValue(__instance) as Array, (int i) => new Vector2i(i, 0));
				int actionRow = 0;
				bool flag = false;
				if (_actionRow != null)
				{
					actionRow = (int)_actionRow.Invoke(null, new object[1] { val });
					flag = true;
				}
				if (flag)
				{
					AttachSlotArray(_hotbarActions?.GetValue(__instance) as Array, (int i) => new Vector2i(i, actionRow));
				}
				if (!_loggedHotbar)
				{
					_loggedHotbar = true;
					Plugin.Log("Attached Skyheim rune cooldown overlays to SeneaL hotbar and action slots.");
				}
			}
			catch (Exception ex)
			{
				if (!_loggedMissing)
				{
					_loggedMissing = true;
					Plugin.LogWarning("Could not attach Skyheim cooldown overlays to SeneaL slots: " + ex.Message);
				}
			}
		}

		private static void AttachSlotArray(Array slots, Func<int, Vector2i> locationForIndex)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (slots == null || _slotRoot == null)
			{
				return;
			}
			for (int i = 0; i < slots.Length; i++)
			{
				object value = slots.GetValue(i);
				if (value != null)
				{
					object? value2 = _slotRoot.GetValue(value);
					RectTransform val = (RectTransform)((value2 is RectTransform) ? value2 : null);
					if (Object.op_Implicit((Object)(object)val))
					{
						CooldownPrefab.EnsureOn((Transform)(object)val, locationForIndex(i));
					}
				}
			}
		}
	}
	internal static class CooldownPrefab
	{
		private static readonly FieldInfo LocationField = AccessTools.Field(typeof(SkyheimCooldownItem), "<Location>k__BackingField");

		internal static Vector2i GetLocation(SkyheimCooldownItem item)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)item == (Object)null))
			{
				return item.Location;
			}
			return new Vector2i(-1, -1);
		}

		internal static void SetLocation(SkyheimCooldownItem item, Vector2i location)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			LocationField?.SetValue(item, location);
		}

		internal static GameObject Get()
		{
			if (SkyheimCooldown.Instance == null)
			{
				return null;
			}
			object? obj = AccessTools.Field(typeof(SkyheimCooldown), "_cooldownPrefab")?.GetValue(SkyheimCooldown.Instance);
			return (GameObject)((obj is GameObject) ? obj : null);
		}

		internal static void EnsureOn(Transform parent, Vector2i location)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)parent))
			{
				return;
			}
			SkyheimCooldownItem componentInChildren = ((Component)parent).GetComponentInChildren<SkyheimCooldownItem>(true);
			if (Object.op_Implicit((Object)(object)componentInChildren))
			{
				GameObject gameObject = ((Component)componentInChildren).gameObject;
				if (Object.op_Implicit((Object)(object)gameObject) && !gameObject.activeSelf)
				{
					gameObject.SetActive(true);
				}
				Vector2i location2 = GetLocation(componentInChildren);
				if (location2.x != location.x || location2.y != location.y)
				{
					SetLocation(componentInChildren, location);
					if (SkyheimCooldown.Instance != null)
					{
						SkyheimCooldown.Instance.RegisterUpdateable(componentInChildren);
					}
				}
				return;
			}
			GameObject val = Get();
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, parent);
			((Object)val2).name = "skyheim_cooldown";
			Transform transform = val2.transform;
			Stretch((RectTransform)(object)((transform is RectTransform) ? transform : null));
			val2.SetActive(true);
			SkyheimCooldownItem val3 = val2.GetComponent<SkyheimCooldownItem>() ?? val2.GetComponentInChildren<SkyheimCooldownItem>(true);
			if (!((Object)(object)val3 == (Object)null))
			{
				SetLocation(val3, location);
				if (SkyheimCooldown.Instance != null)
				{
					SkyheimCooldown.Instance.RegisterUpdateable(val3);
				}
			}
		}

		private static void Stretch(RectTransform rt)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)rt))
			{
				rt.anchorMin = Vector2.zero;
				rt.anchorMax = Vector2.one;
				rt.offsetMin = Vector2.zero;
				rt.offsetMax = Vector2.zero;
				((Transform)rt).localScale = Vector3.one;
				((Transform)rt).SetAsLastSibling();
			}
		}
	}
	[HarmonyPatch(typeof(InventoryGrid), "UpdateGui")]
	internal static class InventoryGrid_UpdateGui_Cooldown_Patch
	{
		private static void Postfix(InventoryGrid __instance)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || __instance.m_elements == null)
			{
				return;
			}
			foreach (InventoryElement element in __instance.m_elements)
			{
				if (Object.op_Implicit((Object)(object)element))
				{
					CooldownPrefab.EnsureOn(((Component)element).transform, element.Position);
				}
			}
		}
	}
	[HarmonyPatch(typeof(SkyheimCooldown), "Update")]
	internal static class SkyheimCooldown_Update_Patch
	{
		private static readonly FieldInfo Updateables = AccessTools.Field(typeof(SkyheimCooldown), "_updateables");

		private static void Prefix(SkyheimCooldown __instance)
		{
			if (!(Updateables?.GetValue(__instance) is List<SkyheimCooldownItem> list))
			{
				return;
			}
			for (int num = list.Count - 1; num >= 0; num--)
			{
				if (!Object.op_Implicit((Object)(object)list[num]))
				{
					list.RemoveAt(num);
				}
			}
		}
	}
	[HarmonyPatch(typeof(SkyheimCooldownItem), "Awake")]
	internal static class SkyheimCooldownItem_Awake_Patch
	{
		private static bool Prefix()
		{
			return false;
		}
	}
	[HarmonyPatch(typeof(HotkeyBar), "Update")]
	internal static class HotkeyBar_Update_Cooldown_Patch
	{
		private static void Postfix(HotkeyBar __instance)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.SenealUiLoaded() || (Object)(object)__instance == (Object)null || __instance.m_elements == null)
			{
				return;
			}
			for (int i = 0; i < __instance.m_elements.Count; i++)
			{
				GameObject go = __instance.m_elements[i].m_go;
				if (Object.op_Implicit((Object)(object)go))
				{
					CooldownPrefab.EnsureOn(go.transform, new Vector2i(i, 0));
				}
			}
		}
	}
	[HarmonyPatch(typeof(SkyheimCooldownItem), "SetCooldown")]
	internal static class SkyheimCooldownItem_SetCooldown_Patch
	{
		private static readonly FieldInfo Swipe = AccessTools.Field(typeof(SkyheimCooldownItem), "_swipe");

		private static readonly FieldInfo Label = AccessTools.Field(typeof(SkyheimCooldownItem), "_text");

		private static bool Prefix(SkyheimCooldownItem __instance)
		{
			if (!Object.op_Implicit((Object)(object)__instance))
			{
				return false;
			}
			if (Swipe?.GetValue(__instance) is Image)
			{
				return Label?.GetValue(__instance) is Text;
			}
			return false;
		}
	}
	internal static class SkyheimAudio
	{
		[HarmonyPatch(typeof(ZSFX), "Play")]
		private static class ZSFX_Play_Patch
		{
			private static void Prefix(ZSFX __instance)
			{
				if (ShouldScale(__instance))
				{
					Scale(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Attack), "Start")]
		[HarmonyPatch(typeof(Attack), "OnAttackTrigger")]
		[HarmonyPatch(typeof(Attack), "FireProjectileBurst")]
		[HarmonyPatch(typeof(Attack), "ProjectileAttackTriggered")]
		[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
		[HarmonyPatch(typeof(Attack), "DoAreaAttack")]
		private static class Attack_AudioScope_Patch
		{
			private static void Prefix(Attack __instance, ref bool __state)
			{
				__state = IsSkyheimWeapon(__instance);
				if (__state)
				{
					Enter();
				}
			}

			private static void Finalizer(bool __state)
			{
				if (__state)
				{
					Exit();
				}
			}
		}

		[HarmonyPatch(typeof(Aoe), "OnHit")]
		private static class Aoe_OnHit_AudioScope_Patch
		{
			private static void Prefix(Aoe __instance, ref bool __state)
			{
				__state = IsSkyheimObject(((Object)(object)__instance != (Object)null) ? ((Component)__instance).gameObject : null);
				if (__state)
				{
					Enter();
				}
			}

			private static void Finalizer(bool __state)
			{
				if (__state)
				{
					Exit();
				}
			}
		}

		[HarmonyPatch(typeof(StatusEffect), "Setup")]
		private static class StatusEffect_Setup_AudioScope_Patch
		{
			private static void Prefix(StatusEffect __instance, ref bool __state)
			{
				__state = IsSkyheimStatus(__instance);
				if (__state)
				{
					Enter();
				}
			}

			private static void Finalizer(bool __state)
			{
				if (__state)
				{
					Exit();
				}
			}
		}

		[HarmonyPatch(typeof(Projectile), "OnHit")]
		private static class Projectile_OnHit_AudioScope_Patch
		{
			private static void Prefix(Projectile __instance, ref bool __state)
			{
				__state = IsSkyheimObject(((Object)(object)__instance != (Object)null) ? ((Component)__instance).gameObject : null);
				if (__state)
				{
					Enter();
				}
			}

			private static void Finalizer(bool __state)
			{
				if (__state)
				{
					Exit();
				}
			}
		}

		private const float DefaultVolume = 0.5f;

		private static readonly Dictionary<string, ConfigEntry<float>> Volumes = new Dictionary<string, ConfigEntry<float>>(StringComparer.Ordinal);

		private static readonly HashSet<int> Scaled = new HashSet<int>();

		private static readonly HashSet<int> BundleObjects = new HashSet<int>();

		private static int _depth;

		internal static void Bind(ConfigFile config)
		{
			Discover(config);
		}

		internal static void Apply(Harmony harmony)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Expected O, but got Unknown
			//IL_0079: Expected O, but got Unknown
			Type[] nestedTypes = typeof(ChainAoe).GetNestedTypes(BindingFlags.NonPublic);
			foreach (Type type in nestedTypes)
			{
				if (type.Name.IndexOf("StaggerVisuals", StringComparison.Ordinal) >= 0)
				{
					MethodInfo method = type.GetMethod("MoveNext", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (!(method == null))
					{
						harmony.Patch((MethodBase)method, new HarmonyMethod(typeof(SkyheimAudio), "Enter", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(SkyheimAudio), "Exit", (Type[])null), (HarmonyMethod)null);
					}
				}
			}
		}

		internal static void Enter()
		{
			_depth++;
		}

		internal static void Exit()
		{
			if (_depth > 0)
			{
				_depth--;
			}
		}

		internal static void ScaleObject(GameObject instance)
		{
			if (!((Object)(object)instance == (Object)null))
			{
				ZSFX[] componentsInChildren = instance.GetComponentsInChildren<ZSFX>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					Scale(componentsInChildren[i]);
				}
			}
		}

		private static void Discover(ConfigFile config)
		{
			if (AssetManager.AssetBundleObjects == null)
			{
				return;
			}
			for (int i = 0; i < AssetManager.AssetBundleObjects.Length; i++)
			{
				Object obj = AssetManager.AssetBundleObjects[i];
				GameObject val = (GameObject)(object)((obj is GameObject) ? obj : null);
				if (val != null)
				{
					RememberBundleObject(val);
				}
			}
			for (int j = 0; j < AssetManager.AssetBundleObjects.Length; j++)
			{
				Object obj2 = AssetManager.AssetBundleObjects[j];
				GameObject val2 = (GameObject)(object)((obj2 is GameObject) ? obj2 : null);
				if (val2 == null)
				{
					continue;
				}
				ZSFX[] componentsInChildren = val2.GetComponentsInChildren<ZSFX>(true);
				for (int k = 0; k < componentsInChildren.Length; k++)
				{
					EnsureMark(componentsInChildren[k]);
					BindVolume(config, ((Object)((Component)componentsInChildren[k]).gameObject).name);
				}
				Component[] componentsInChildren2 = val2.GetComponentsInChildren<Component>(true);
				foreach (Component val3 in componentsInChildren2)
				{
					if ((Object)(object)val3 == (Object)null)
					{
						continue;
					}
					FieldInfo[] fields = ((object)val3).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					for (int m = 0; m < fields.Length; m++)
					{
						if (!(fields[m].FieldType != typeof(EffectList)))
						{
							object? value = fields[m].GetValue(val3);
							EffectList val4 = (EffectList)((value is EffectList) ? value : null);
							if (val4 != null)
							{
								RegisterEffectList(config, val4);
							}
						}
					}
				}
			}
			BindVolume(config, "vfx_Potion_health_medium");
			BindVolume(config, "vfx_Heal");
		}

		private static void RememberBundleObject(GameObject go)
		{
			BundleObjects.Add(((Object)go).GetInstanceID());
			Transform[] componentsInChildren = go.GetComponentsInChildren<Transform>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				BundleObjects.Add(((Object)((Component)componentsInChildren[i]).gameObject).GetInstanceID());
			}
		}

		private static void RegisterEffectList(ConfigFile config, EffectList list)
		{
			if (list?.m_effectPrefabs == null)
			{
				return;
			}
			for (int i = 0; i < list.m_effectPrefabs.Length; i++)
			{
				GameObject prefab = list.m_effectPrefabs[i].m_prefab;
				if ((Object)(object)prefab == (Object)null)
				{
					continue;
				}
				ZSFX[] componentsInChildren = prefab.GetComponentsInChildren<ZSFX>(true);
				if (componentsInChildren.Length == 0)
				{
					BindVolume(config, ((Object)prefab).name);
					continue;
				}
				bool flag = BundleObjects.Contains(((Object)prefab).GetInstanceID());
				for (int j = 0; j < componentsInChildren.Length; j++)
				{
					if (flag || BundleObjects.Contains(((Object)((Component)componentsInChildren[j]).gameObject).GetInstanceID()))
					{
						EnsureMark(componentsInChildren[j]);
					}
					BindVolume(config, ((Object)((Component)componentsInChildren[j]).gameObject).name);
				}
			}
		}

		private static void EnsureMark(ZSFX sound)
		{
			if ((Object)(object)sound != (Object)null && (Object)(object)((Component)sound).GetComponent<SkyheimSfxMark>() == (Object)null)
			{
				((Component)sound).gameObject.AddComponent<SkyheimSfxMark>();
			}
		}

		private static void BindVolume(ConfigFile config, string objectName)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			if (!string.IsNullOrEmpty(objectName) && !Volumes.ContainsKey(objectName))
			{
				Volumes[objectName] = config.Bind<float>("Audio", objectName, 0.5f, new ConfigDescription("Volume scale for this Skyheim sound. 1 is the prefab's full volume.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			}
		}

		private static void Scale(ZSFX sound)
		{
			if ((Object)(object)sound == (Object)null || !Scaled.Add(((Object)sound).GetInstanceID()))
			{
				return;
			}
			if (!Volumes.TryGetValue(((Object)((Component)sound).gameObject).name, out var value) || value == null)
			{
				if ((Object)(object)Plugin.Instance != (Object)null)
				{
					BindVolume(((BaseUnityPlugin)Plugin.Instance).Config, ((Object)((Component)sound).gameObject).name);
				}
				if (!Volumes.TryGetValue(((Object)((Component)sound).gameObject).name, out value) || value == null)
				{
					return;
				}
			}
			float num = Mathf.Clamp01(value.Value);
			sound.m_minVol *= num;
			sound.m_maxVol *= num;
			AudioSource component = ((Component)sound).GetComponent<AudioSource>();
			if ((Object)(object)component != (Object)null)
			{
				component.volume *= num;
			}
		}

		private static bool ShouldScale(ZSFX sound)
		{
			if ((Object)(object)sound == (Object)null)
			{
				return false;
			}
			if ((Object)(object)((Component)sound).GetComponent<SkyheimSfxMark>() != (Object)null)
			{
				return true;
			}
			return _depth > 0;
		}

		private static bool IsSkyheimWeapon(Attack attack)
		{
			Humanoid val = attack?.m_character;
			if (val == null)
			{
				return false;
			}
			return IsSkyheimObject(val.GetCurrentWeapon()?.m_dropPrefab);
		}

		private static bool IsSkyheimStatus(StatusEffect effect)
		{
			if ((Object)(object)effect == (Object)null)
			{
				return false;
			}
			return (((object)effect).GetType().Assembly.GetName().Name ?? string.Empty).IndexOf("skyheim", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static bool IsSkyheimObject(GameObject go)
		{
			if ((Object)(object)go == (Object)null)
			{
				return false;
			}
			string text = ((Object)go).name ?? string.Empty;
			if (text.StartsWith("rune_", StringComparison.OrdinalIgnoreCase) || text.StartsWith("sh_", StringComparison.OrdinalIgnoreCase) || text.IndexOf("skyheim", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				return true;
			}
			MonoBehaviour[] components = go.GetComponents<MonoBehaviour>();
			foreach (MonoBehaviour val in components)
			{
				if (!((Object)(object)val == (Object)null) && (((object)val).GetType().Assembly.GetName().Name ?? string.Empty).IndexOf("skyheim", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal sealed class SkyheimSfxMark : MonoBehaviour
	{
	}
	internal static class WindfuryDamageGuard
	{
		private static readonly FieldInfo WindfuryHash = AccessTools.Field(typeof(SkyheimPlugin), "_statusEffectWindfury");

		internal static void RemoveOriginal(Harmony unused)
		{
			Unpatch(typeof(Character), "Damage", (HarmonyPatchType)2, "SkyheimPlugin");
			Unpatch(typeof(HitData), "SetAttacker", (HarmonyPatchType)2, "SkyheimPlugin");
			if (AccessTools.DeclaredMethod(typeof(Character), "RPC_Damage", (Type[])null, (Type[])null) != null)
			{
				Unpatch(typeof(Character), "RPC_Damage", (HarmonyPatchType)1, "SkyheimPlugin");
			}
		}

		private static void Unpatch(Type originalType, string methodName, HarmonyPatchType kind, string declaringTypeName)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			MethodInfo methodInfo = AccessTools.DeclaredMethod(originalType, methodName, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				return;
			}
			Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
			if (patchInfo == null)
			{
				return;
			}
			foreach (Patch item in (IEnumerable<Patch>)(((int)kind == 1) ? patchInfo.Prefixes : patchInfo.Postfixes))
			{
				if (!(item.PatchMethod?.DeclaringType?.Name != declaringTypeName))
				{
					new Harmony(item.owner).Unpatch((MethodBase)methodInfo, item.PatchMethod);
					Plugin.Log("Removed Skyheim " + declaringTypeName + " " + originalType.Name + "." + methodName + " null crash.");
				}
			}
		}

		internal static int WindfuryStatusHash()
		{
			if (!(WindfuryHash == null))
			{
				return (int)WindfuryHash.GetValue(null);
			}
			return 0;
		}
	}
	[HarmonyPatch(typeof(Character), "Damage")]
	internal static class Character_Damage_Windfury_Patch
	{
		private static void Postfix(Character __instance, HitData hit)
		{
			if (!Object.op_Implicit((Object)(object)__instance) || hit == null || !Object.op_Implicit((Object)(object)__instance.m_nview) || !__instance.m_nview.IsValid())
			{
				return;
			}
			Character attacker = hit.GetAttacker();
			if (!Object.op_Implicit((Object)(object)attacker) || (Object)(object)attacker != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			SEMan sEMan = attacker.GetSEMan();
			int num = WindfuryDamageGuard.WindfuryStatusHash();
			if (sEMan != null && num != 0 && sEMan.HaveStatusEffect(num))
			{
				StatusEffect statusEffect = sEMan.GetStatusEffect(num);
				SE_Windfury val = (SE_Windfury)(object)((statusEffect is SE_Windfury) ? statusEffect : null);
				if (!((Object)(object)val == (Object)null))
				{
					val.OnDamageDealt(__instance, hit);
				}
			}
		}
	}
	[HarmonyPatch(typeof(HitData), "SetAttacker")]
	internal static class HitData_SetAttacker_Patch
	{
		private static void Postfix(HitData __instance, Character attacker)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)attacker) || !attacker.IsPlayer())
			{
				return;
			}
			Player val = (Player)(object)((attacker is Player) ? attacker : null);
			ItemData val2 = (((Object)(object)val != (Object)null) ? ((Humanoid)val).GetCurrentWeapon() : null);
			if (!((Object)(object)val2?.m_dropPrefab == (Object)null))
			{
				SkyheimItemData component = val2.m_dropPrefab.GetComponent<SkyheimItemData>();
				if ((Object)(object)component != (Object)null && component.Beneficial)
				{
					__instance.m_attacker = ZDOID.None;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Character), "RPC_Damage")]
	internal static class Character_RPC_Damage_Patch
	{
		private static void Prefix(Character __instance, HitData hit)
		{
			if (Object.op_Implicit((Object)(object)__instance) && hit != null && hit.m_statusEffectHash != 0 && __instance.m_seman != null)
			{
				__instance.m_seman.RemoveStatusEffect(hit.m_statusEffectHash, true);
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}