Decompiled source of OdinRegalia v1.0.0

OdinRegalia.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using Gungnir;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("OdinRegalia")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("OdinRegalia")]
[assembly: AssemblyTitle("OdinRegalia")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 OdinArmour
{
	[BepInPlugin("com.crasssam.odinarmour", "Odin's Regalia", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class OdinArmourPlugin : BaseUnityPlugin
	{
		public const string Guid = "com.crasssam.odinarmour";

		public const string Version = "1.0.0";

		private Harmony _harmony;

		private float _nextAuraCheck;

		private bool? _lastSyncedWearing;

		private ZNetView _lastView;

		private bool _checkedCape;

		private OdinEyeGlow _eye;

		private void Awake()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			_harmony = new Harmony("com.crasssam.odinarmour");
			PrefabManager.OnVanillaPrefabsAvailable += Register;
			TryPatch(typeof(OdinEitrPatch));
			TryPatch(typeof(OdinChestVisualPatch));
			TryPatch(typeof(OdinCrownJewelPatch));
			TryPatch(typeof(GungnirImpactPatch));
			TryPatch(typeof(GungnirSummonInput));
			_eye = ((Component)this).gameObject.AddComponent<OdinEyeGlow>();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Odin Armour 1.0.0 loaded; awaiting vanilla prefabs");
		}

		private void TryPatch(Type patch)
		{
			try
			{
				_harmony.CreateClassProcessor(patch).Patch();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Odin Armour patch " + patch.Name + " failed: " + ex));
			}
		}

		private void OnDestroy()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= Register;
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}

		private void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable -= Register;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Odin Armour registering equipment");
			try
			{
				OdinEquipment.Register();
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Odin Armour item registration failed: " + ex));
			}
			try
			{
				OdinPresence.Register();
			}
			catch (Exception ex2)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Odin's Presence registration failed: " + ex2));
			}
			GungnirPlugin.Register();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Odin Armour registration pass completed");
		}

		private void Update()
		{
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			if (!_checkedCape && (Object)(object)ObjectDB.instance != (Object)null && (Object)(object)ZNetScene.instance != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				_checkedCape = true;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("OdinArmourCape lookup: ObjectDB=" + ((Object)(object)ObjectDB.instance.GetItemPrefab("OdinArmourCape") != (Object)null) + ", ZNetScene=" + ((Object)(object)ZNetScene.instance.GetPrefab("OdinArmourCape") != (Object)null)));
			}
			if (Time.time < _nextAuraCheck)
			{
				return;
			}
			_nextAuraCheck = Time.time + 1f;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			bool flag = OdinEquipment.HasFullSet(localPlayer);
			OdinEitrPatch.Sync(localPlayer, flag);
			ZNetView component = ((Component)localPlayer).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)(object)_lastView)
			{
				_lastView = component;
				_lastSyncedWearing = null;
			}
			if ((Object)(object)component != (Object)null && component.IsValid() && component.IsOwner() && (!_lastSyncedWearing.HasValue || flag != _lastSyncedWearing.Value))
			{
				component.GetZDO().Set("com.crasssam.odinarmour.fullset", flag);
				_lastSyncedWearing = flag;
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Odin Armour four-piece set " + (flag ? "active" : "inactive")));
			}
			_eye.Tick(localPlayer, OdinEquipment.IsWearingHood(localPlayer));
			if ((Object)(object)OdinPresence.Effect == (Object)null)
			{
				return;
			}
			if (flag)
			{
				OdinPresence.Refresh(localPlayer);
				return;
			}
			bool flag2 = false;
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if (!((Object)(object)allPlayer == (Object)null) && !((Object)(object)allPlayer == (Object)(object)localPlayer) && !(Vector3.Distance(((Component)allPlayer).transform.position, ((Component)localPlayer).transform.position) > 12f) && !BaseAI.IsEnemy((Character)(object)allPlayer, (Character)(object)localPlayer))
				{
					ZNetView component2 = ((Component)allPlayer).GetComponent<ZNetView>();
					if ((Object)(object)component2 != (Object)null && component2.IsValid() && component2.GetZDO().GetBool("com.crasssam.odinarmour.fullset", false))
					{
						flag2 = true;
						break;
					}
				}
			}
			if (flag2)
			{
				OdinPresence.Refresh(localPlayer);
			}
			else
			{
				OdinPresence.Remove(localPlayer);
			}
		}
	}
	internal static class OdinEquipment
	{
		private static readonly BindingFlags Fields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly FieldInfo HelmetSlot = typeof(Humanoid).GetField("m_helmetItem", Fields);

		private static readonly FieldInfo ChestSlot = typeof(Humanoid).GetField("m_chestItem", Fields);

		private static readonly FieldInfo LegsSlot = typeof(Humanoid).GetField("m_legItem", Fields);

		private static readonly FieldInfo CapeSlot = typeof(Humanoid).GetField("m_shoulderItem", Fields);

		private static readonly HashSet<Requirement> CrownJewelRequirements = new HashSet<Requirement>();

		internal static Sprite HoodIcon { get; private set; }

		internal static void Register()
		{
			TryAdd("OdinHood", delegate
			{
				Add("OdinHood", "HelmetMage_Ashlands", "HelmetDNHeavy", "Hood of Odin", "A black hood with one glowing red eye. Part of Odin's four-piece regalia.", "HelmetMage_Ashlands", 20, 5, "NornThread", 5, 2, invisibleChest: false);
			});
			TryAdd("OdinChest", delegate
			{
				Add("OdinChest", "ArmorFlametalChest", "ArmorDeepNorthHeavyChest", "Odin's Hidden Mail", "Invisible armour that leaves your normal torso visible.", "ArmorFlametalChest", 20, 10, "MooseHide", 8, 3, invisibleChest: true);
			});
			TryAdd("OdinLegs", delegate
			{
				Add("OdinLegs", "ArmorAshlandsMediumlegs", "ArmorDeepNorthHeavylegs", "Trousers of Odin", "The shadowed trousers of the Allfather.", "ArmorAshlandsMediumlegs", 20, 10, "MooseHide", 8, 3, invisibleChest: false);
			});
			TryAdd("OdinArmourCape", delegate
			{
				Add("OdinArmourCape", "CapeLox", null, "Mantle of Odin", "A dark lox cape with frost resistance and slow fall.", "CapeLox", 10, 3, "MooseHide", 6, 2, invisibleChest: false);
			});
		}

		private static void TryAdd(string name, Action register)
		{
			try
			{
				register();
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[OdinArmour] Could not register " + name + ": " + ex));
			}
		}

		private static void Add(string prefabName, string basePrefab, string armorReference, string displayName, string description, string ingredient, int bloodgold, int bloodgoldUpgrade, string extraIngredient, int extraAmount, int extraUpgrade, bool invisibleChest)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			ItemConfig val = new ItemConfig
			{
				Name = displayName,
				Description = description,
				CraftingStation = "blackforge",
				MinStationLevel = 2
			};
			val.AddRequirement(new RequirementConfig(ingredient, 1, 0, true));
			val.AddRequirement(new RequirementConfig("Gold", bloodgold, bloodgoldUpgrade, true));
			val.AddRequirement(new RequirementConfig(extraIngredient, extraAmount, extraUpgrade, true));
			val.AddRequirement(new RequirementConfig("CrownJewel", 1, 1, true));
			CustomItem val2 = new CustomItem(prefabName, basePrefab, val);
			if ((Object)(object)val2.ItemPrefab == (Object)null || (Object)(object)val2.ItemDrop == (Object)null)
			{
				throw new InvalidOperationException("Could not clone " + basePrefab + " as " + prefabName + ". Check the log for a prefab name collision or missing source item.");
			}
			Recipe val3 = ((val2.Recipe == null) ? null : val2.Recipe.Recipe);
			if ((Object)(object)val3 == (Object)null || val3.m_resources == null || val3.m_resources.Length != 4 || val3.m_resources[3] == null)
			{
				throw new InvalidOperationException("Could not create the Crown Jewel recipe for " + prefabName);
			}
			ItemData itemData = val2.ItemDrop.m_itemData;
			itemData.m_shared = ShallowCopy<SharedData>(itemData.m_shared);
			SharedData shared = itemData.m_shared;
			shared.m_name = "$item_odinarmour_" + prefabName;
			shared.m_description = "$item_odinarmour_desc_" + prefabName;
			shared.m_movementModifier = 0f;
			SetIfExists(shared, "m_setName", "OdinArmourFourPieces");
			SetIfExists(shared, "m_setSize", 4);
			SetIfExists(shared, "m_setStatusEffect", null);
			if (armorReference != null)
			{
				GameObject prefab = PrefabManager.Instance.GetPrefab(armorReference);
				if ((Object)(object)prefab == (Object)null)
				{
					throw new InvalidOperationException("Missing armour reference: " + armorReference);
				}
				SharedData shared2 = prefab.GetComponent<ItemDrop>().m_itemData.m_shared;
				CopyField(shared2, shared, "m_armor");
				CopyField(shared2, shared, "m_armorPerLevel");
				SetIfExists(shared, "m_equipStatusEffect", null);
			}
			Darken(val2.ItemPrefab, invisibleChest);
			Sprite val4 = DarkIcon(shared.m_icons);
			if ((Object)(object)val4 != (Object)null)
			{
				shared.m_icons = (Sprite[])(object)new Sprite[1] { val4 };
			}
			if (prefabName == "OdinHood" && shared.m_icons != null && shared.m_icons.Length != 0)
			{
				HoodIcon = shared.m_icons[0];
			}
			if (!ItemManager.Instance.AddItem(val2))
			{
				throw new InvalidOperationException("Jötunn rejected " + prefabName + "; see the Jötunn warnings in the BepInEx log.");
			}
			CrownJewelRequirements.Add(val3.m_resources[3]);
			if (prefabName == "OdinArmourCape")
			{
				try
				{
					OdinPresence.ConfigureCape(shared);
				}
				catch (Exception ex)
				{
					Debug.LogError((object)("[OdinArmour] OdinArmourCape registered, but slow fall failed: " + ex));
				}
			}
			Debug.Log((object)("[OdinArmour] Jötunn accepted " + prefabName));
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				["item_odinarmour_" + prefabName] = displayName,
				["item_odinarmour_desc_" + prefabName] = description
			});
		}

		private static T ShallowCopy<T>(T value) where T : class
		{
			return (T)typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(value, null);
		}

		internal static bool IsCrownJewelRequirement(Requirement requirement)
		{
			return CrownJewelRequirements.Contains(requirement);
		}

		private static void CopyField(object source, object target, string name)
		{
			FieldInfo field = source.GetType().GetField(name, Fields);
			if (field == null)
			{
				throw new MissingFieldException(source.GetType().FullName, name);
			}
			field.SetValue(target, field.GetValue(source));
		}

		internal static bool SetIfExists(object target, string name, object value)
		{
			FieldInfo field = target.GetType().GetField(name, Fields);
			if (field == null)
			{
				return false;
			}
			field.SetValue(target, value);
			return true;
		}

		internal static bool HasFullSet(Player player)
		{
			if ((Object)(object)player != (Object)null && Is(HelmetSlot, player, "OdinHood") && Is(ChestSlot, player, "OdinChest") && Is(LegsSlot, player, "OdinLegs"))
			{
				return Is(CapeSlot, player, "OdinArmourCape");
			}
			return false;
		}

		internal static bool IsWearingHood(Player player)
		{
			if ((Object)(object)player != (Object)null)
			{
				return Is(HelmetSlot, player, "OdinHood");
			}
			return false;
		}

		private static bool Is(FieldInfo slot, Player player, string name)
		{
			ItemData val = (ItemData)((slot == null) ? null : /*isinst with value type is only supported in some contexts*/);
			if (val != null && val.m_shared != null)
			{
				return val.m_shared.m_name == "$item_odinarmour_" + name;
			}
			return false;
		}

		private static void Darken(GameObject root, bool invisibleChest)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			Color val3 = default(Color);
			foreach (Renderer val in componentsInChildren)
			{
				if (invisibleChest && val is SkinnedMeshRenderer)
				{
					val.enabled = false;
					continue;
				}
				Material[] sharedMaterials = val.sharedMaterials;
				Material[] array = (Material[])(object)new Material[sharedMaterials.Length];
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					if (!((Object)(object)sharedMaterials[j] == (Object)null))
					{
						Material val2 = new Material(sharedMaterials[j]);
						((Color)(ref val3))..ctor(0.018f, 0.019f, 0.024f, 1f);
						if (val2.HasProperty("_Color"))
						{
							val2.SetColor("_Color", val3);
						}
						if (val2.HasProperty("_BaseColor"))
						{
							val2.SetColor("_BaseColor", val3);
						}
						if (val2.HasProperty("_EmissionColor"))
						{
							val2.SetColor("_EmissionColor", Color.black);
						}
						array[j] = val2;
					}
				}
				val.sharedMaterials = array;
			}
		}

		private static Sprite DarkIcon(Sprite[] source)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			if (source == null || source.Length == 0 || (Object)(object)source[0] == (Object)null)
			{
				return null;
			}
			try
			{
				Sprite obj = source[0];
				Texture2D texture = obj.texture;
				Rect textureRect = obj.textureRect;
				int num = Mathf.RoundToInt(((Rect)(ref textureRect)).width);
				int num2 = Mathf.RoundToInt(((Rect)(ref textureRect)).height);
				RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)0);
				RenderTexture active = RenderTexture.active;
				Texture2D val;
				try
				{
					Graphics.Blit((Texture)(object)texture, temporary);
					RenderTexture.active = temporary;
					val = new Texture2D(num, num2, (TextureFormat)4, false);
					val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0);
					val.Apply();
				}
				finally
				{
					RenderTexture.active = active;
					RenderTexture.ReleaseTemporary(temporary);
				}
				Color[] pixels = val.GetPixels();
				for (int i = 0; i < pixels.Length; i++)
				{
					float grayscale = ((Color)(ref pixels[i])).grayscale;
					pixels[i] = new Color(0.012f + grayscale * 0.12f, 0.012f + grayscale * 0.11f, 0.018f + grayscale * 0.13f, pixels[i].a);
				}
				val.SetPixels(pixels);
				val.Apply();
				return Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num2), new Vector2(0.5f, 0.5f));
			}
			catch
			{
				return null;
			}
		}
	}
	[HarmonyPatch(typeof(VisEquipment), "SetChestItem")]
	internal static class OdinChestVisualPatch
	{
		private static void Prefix(ref int itemHash)
		{
			if (itemHash != 0 && !((Object)(object)ObjectDB.instance == (Object)null))
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(itemHash);
				if ((Object)(object)itemPrefab != (Object)null && ((Object)itemPrefab).name == "OdinChest")
				{
					itemHash = 0;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Requirement), "GetAmount")]
	internal static class OdinCrownJewelPatch
	{
		private static void Postfix(Requirement __instance, int qualityLevel, ref int __result)
		{
			if (qualityLevel > 1 && OdinEquipment.IsCrownJewelRequirement(__instance))
			{
				__result = 1;
			}
		}
	}
	[HarmonyPatch]
	internal static class OdinEitrPatch
	{
		private const float Bonus = 50f;

		private static readonly BindingFlags Methods = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly MethodInfo SetMaximum = typeof(Player).GetMethod("SetMaxEitr", Methods, null, new Type[2]
		{
			typeof(float),
			typeof(bool)
		}, null);

		private static readonly MethodInfo GetFoodValues = typeof(Player).GetMethod("GetTotalFoodValue", Methods, null, new Type[3]
		{
			typeof(float).MakeByRefType(),
			typeof(float).MakeByRefType(),
			typeof(float).MakeByRefType()
		}, null);

		private static Player _lastPlayer;

		private static bool? _lastWearing;

		private static MethodBase TargetMethod()
		{
			if (SetMaximum == null)
			{
				throw new MissingMethodException("Player.SetMaxEitr(float, bool)");
			}
			return SetMaximum;
		}

		private static void Prefix(Player __instance, ref float __0)
		{
			if (OdinEquipment.HasFullSet(__instance))
			{
				__0 += 50f;
			}
		}

		internal static void Sync(Player player, bool wearing)
		{
			if ((Object)(object)_lastPlayer != (Object)(object)player)
			{
				_lastPlayer = player;
				_lastWearing = null;
			}
			if (_lastWearing == wearing)
			{
				return;
			}
			if (!_lastWearing.HasValue && !wearing)
			{
				_lastWearing = false;
				return;
			}
			if (SetMaximum == null || GetFoodValues == null)
			{
				Debug.LogError((object)"[OdinArmour] Could not recalculate Eitr: Player food or Eitr setter method is missing");
				return;
			}
			try
			{
				object[] array = new object[3] { 0f, 0f, 0f };
				GetFoodValues.Invoke(player, array);
				SetMaximum.Invoke(player, new object[2]
				{
					(float)array[2],
					false
				});
				_lastWearing = wearing;
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[OdinArmour] Could not recalculate Eitr after set change: " + ex));
			}
		}
	}
	internal sealed class OdinEyeGlow : MonoBehaviour
	{
		private static readonly Vector3 EyeOffset = new Vector3(0.075f, 0.065f, 0.225f);

		private GameObject _eye;

		private Player _owner;

		internal void Tick(Player player, bool hoodEquipped)
		{
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			if (!hoodEquipped)
			{
				if ((Object)(object)_eye != (Object)null)
				{
					_eye.SetActive(false);
				}
				return;
			}
			if ((Object)(object)_owner != (Object)(object)player || (Object)(object)_eye == (Object)null)
			{
				if ((Object)(object)_eye != (Object)null)
				{
					Object.Destroy((Object)(object)_eye);
				}
				_owner = player;
				Transform val = null;
				Animator componentInChildren = ((Component)player).GetComponentInChildren<Animator>(true);
				if ((Object)(object)componentInChildren != (Object)null && componentInChildren.isHuman)
				{
					try
					{
						val = componentInChildren.GetBoneTransform((HumanBodyBones)10);
					}
					catch (Exception)
					{
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					Transform[] componentsInChildren = ((Component)player).GetComponentsInChildren<Transform>(true);
					foreach (Transform val2 in componentsInChildren)
					{
						if (string.Equals(((Object)val2).name, "Head", StringComparison.OrdinalIgnoreCase))
						{
							val = val2;
							break;
						}
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				_eye = new GameObject("OdinArmour_RightEyeLight");
				_eye.transform.SetParent(val, false);
				_eye.transform.localPosition = EyeOffset;
				Light obj = _eye.AddComponent<Light>();
				obj.color = new Color(1f, 0.025f, 0.025f);
				obj.intensity = 1.2f;
				obj.range = 0.16f;
			}
			_eye.SetActive(true);
		}

		private void OnDestroy()
		{
			if ((Object)(object)_eye != (Object)null)
			{
				Object.Destroy((Object)(object)_eye);
			}
		}
	}
	internal static class OdinPresence
	{
		private static readonly BindingFlags Fields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		internal static StatusEffect Effect { get; private set; }

		internal static void ConfigureCape(SharedData shared)
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab("CapeFeather");
			ItemDrop val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<ItemDrop>() : null);
			StatusEffect val2 = (((Object)(object)val != (Object)null) ? val.m_itemData.m_shared.m_equipStatusEffect : null);
			if ((Object)(object)val2 == (Object)null)
			{
				throw new InvalidOperationException("CapeFeather's slow-fall equip effect was not found");
			}
			AddFrostResistance(shared);
			shared.m_equipStatusEffect = val2;
		}

		private static void AddFrostResistance(SharedData shared)
		{
			FieldInfo fieldInfo = FindField(((object)shared).GetType(), "m_damageModifiers");
			if (fieldInfo == null || !fieldInfo.FieldType.IsGenericType)
			{
				throw new MissingFieldException("SharedData", "m_damageModifiers");
			}
			Type type = fieldInfo.FieldType.GetGenericArguments()[0];
			FieldInfo fieldInfo2 = FindField(type, "m_type");
			FieldInfo fieldInfo3 = FindField(type, "m_modifier");
			if (fieldInfo2 == null || fieldInfo3 == null || !fieldInfo2.FieldType.IsEnum || !fieldInfo3.FieldType.IsEnum)
			{
				throw new MissingFieldException("DamageModPair", "m_type/m_modifier");
			}
			if (!(Activator.CreateInstance(fieldInfo.FieldType) is IList list))
			{
				throw new InvalidOperationException("Cannot copy cape damage modifiers");
			}
			if (fieldInfo.GetValue(shared) is IList list2)
			{
				foreach (object item in list2)
				{
					list.Add(item);
					if (fieldInfo2.GetValue(item).ToString() == "Frost")
					{
						fieldInfo3.SetValue(item, Enum.Parse(fieldInfo3.FieldType, "Resistant"));
						list[list.Count - 1] = item;
						fieldInfo.SetValue(shared, list);
						return;
					}
				}
			}
			object obj = Activator.CreateInstance(type);
			fieldInfo2.SetValue(obj, Enum.Parse(fieldInfo2.FieldType, "Frost"));
			fieldInfo3.SetValue(obj, Enum.Parse(fieldInfo3.FieldType, "Resistant"));
			list.Add(obj);
			fieldInfo.SetValue(shared, list);
		}

		internal static void Register()
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			SE_Stats val = ScriptableObject.CreateInstance<SE_Stats>();
			((Object)val).name = "OdinArmour_Presence";
			((StatusEffect)val).m_name = "Odin's Presence";
			((StatusEffect)val).m_tooltip = "Odin's Presence: +20 armour. Odin's Wisdom: +15% Eitr regeneration. Shared with nearby allies.";
			((StatusEffect)val).m_ttl = 0f;
			((StatusEffect)val).m_icon = OdinEquipment.HoodIcon;
			if (!OdinEquipment.SetIfExists(val, "m_addArmor", 20f) && !OdinEquipment.SetIfExists(val, "m_armorAdd", 20f))
			{
				throw new MissingFieldException("SE_Stats", "m_addArmor");
			}
			if (!OdinEquipment.SetIfExists(val, "m_eitrRegenMultiplier", 1.15f))
			{
				throw new MissingFieldException("SE_Stats", "m_eitrRegenMultiplier");
			}
			if (!ItemManager.Instance.AddStatusEffect(new CustomStatusEffect((StatusEffect)(object)val, false)))
			{
				throw new InvalidOperationException("Jötunn rejected Odin's Presence status effect");
			}
			Effect = (StatusEffect)(object)val;
		}

		internal static void Refresh(Player player)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)Effect == (Object)null)
			{
				return;
			}
			object sEMan = ((Character)player).GetSEMan();
			if (sEMan == null)
			{
				return;
			}
			MethodInfo[] methods = sEMan.GetType().GetMethods(Fields);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name != "AddStatusEffect")
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length == 0 || parameters[0].ParameterType != typeof(StatusEffect))
				{
					continue;
				}
				object[] parameters2;
				if (parameters.Length == 5)
				{
					parameters2 = new object[5]
					{
						Effect,
						true,
						0,
						0f,
						(short)(-1)
					};
				}
				else if (parameters.Length == 4)
				{
					parameters2 = new object[4] { Effect, true, 0, 0f };
				}
				else if (parameters.Length == 2)
				{
					parameters2 = new object[2] { Effect, true };
				}
				else
				{
					if (parameters.Length != 1)
					{
						continue;
					}
					parameters2 = new object[1] { Effect };
				}
				try
				{
					methodInfo.Invoke(sEMan, parameters2);
					break;
				}
				catch
				{
				}
			}
		}

		internal static void Remove(Player player)
		{
			if (!((Object)(object)player == (Object)null) && !((Object)(object)Effect == (Object)null))
			{
				SEMan sEMan = ((Character)player).GetSEMan();
				if (sEMan != null)
				{
					sEMan.RemoveStatusEffect(StringExtensionMethods.GetStableHashCode(((Object)Effect).name), false);
				}
			}
		}

		private static FieldInfo FindField(Type type, string name)
		{
			Type type2 = type;
			while (type2 != null)
			{
				FieldInfo field = type2.GetField(name, Fields | BindingFlags.DeclaredOnly);
				if (field != null)
				{
					return field;
				}
				type2 = type2.BaseType;
			}
			return null;
		}
	}
}
namespace Gungnir
{
	public sealed class GungnirHoming : MonoBehaviour
	{
		private const float LockRange = 60f;

		private const float MinimumAimDot = 0.9063f;

		private const float StraightFlightSeconds = 0.35f;

		private const float TurnRampSeconds = 0.4f;

		private const float TurnRadiansPerSecond = 9f;

		private static readonly BindingFlags Fields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly FieldInfo OwnerField = typeof(Projectile).GetField("m_owner", Fields);

		private static readonly FieldInfo VelocityField = typeof(Projectile).GetField("m_vel", Fields);

		private static readonly FieldInfo GravityField = typeof(Projectile).GetField("m_gravity", Fields);

		private static readonly FieldInfo DidHitField = typeof(Projectile).GetField("m_didHit", Fields);

		private readonly List<Character> _candidates = new List<Character>();

		private Projectile _projectile;

		private ZNetView _network;

		private Character _target;

		private float _speed;

		private float _spawnTime;

		private bool _searched;

		private bool _homingStarted;

		private void Awake()
		{
			_projectile = ((Component)this).GetComponent<Projectile>();
			_network = ((Component)this).GetComponent<ZNetView>();
			_spawnTime = Time.time;
		}

		private void FixedUpdate()
		{
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: 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_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Unknown result type (might be due to invalid IL or missing references)
			//IL_028c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0299: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_projectile == (Object)null || VelocityField == null || OwnerField == null)
			{
				((Behaviour)this).enabled = false;
			}
			else
			{
				if ((Object)(object)_network != (Object)null && !_network.IsOwner())
				{
					return;
				}
				if (!_searched)
				{
					object? value = OwnerField.GetValue(_projectile);
					Character val = (Character)((value is Character) ? value : null);
					if ((Object)(object)val == (Object)null)
					{
						if (Time.time - _spawnTime > 0.5f)
						{
							((Behaviour)this).enabled = false;
						}
						return;
					}
					_searched = true;
					Vector3 val2 = (Vector3)VelocityField.GetValue(_projectile);
					if (((Vector3)(ref val2)).sqrMagnitude < 1f)
					{
						((Behaviour)this).enabled = false;
						return;
					}
					_target = SelectTarget(val);
					if ((Object)(object)_target == (Object)null)
					{
						((Behaviour)this).enabled = false;
						return;
					}
				}
				if ((Object)(object)_target == (Object)null || _target.IsDead() || Vector3.Distance(((Component)this).transform.position, ((Component)_target).transform.position) > 75f)
				{
					((Behaviour)this).enabled = false;
					return;
				}
				if (DidHitField != null && DidHitField.FieldType == typeof(bool) && (bool)DidHitField.GetValue(_projectile))
				{
					((Behaviour)this).enabled = false;
					return;
				}
				Vector3 val3 = (Vector3)VelocityField.GetValue(_projectile);
				if (((Vector3)(ref val3)).sqrMagnitude < 1f)
				{
					((Behaviour)this).enabled = false;
					return;
				}
				float num = Time.time - _spawnTime;
				if (num < 0.35f)
				{
					return;
				}
				if (!_homingStarted)
				{
					_homingStarted = true;
					_speed = ((Vector3)(ref val3)).magnitude;
					if (GravityField != null && GravityField.FieldType == typeof(float))
					{
						GravityField.SetValue(_projectile, 0f);
					}
				}
				Vector3 val4 = _target.GetCenterPoint() - ((Component)this).transform.position;
				if (!(((Vector3)(ref val4)).sqrMagnitude < 0.01f))
				{
					float num2 = Mathf.Clamp01((num - 0.35f) / 0.4f);
					float num3 = Mathf.Lerp(1.5f, 9f, num2);
					Vector3 val5 = Vector3.RotateTowards(((Vector3)(ref val3)).normalized, ((Vector3)(ref val4)).normalized, num3 * Time.fixedDeltaTime, 0f);
					VelocityField.SetValue(_projectile, val5 * _speed);
				}
			}
		}

		private Character SelectTarget(Character owner)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: 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)
			Vector3 eyePoint = owner.GetEyePoint();
			Vector3 lookDir = owner.GetLookDir();
			Vector3 normalized = ((Vector3)(ref lookDir)).normalized;
			Character result = null;
			float num = 0.9063f;
			float num2 = float.MaxValue;
			Character.GetCharactersInRange(eyePoint, 60f, _candidates);
			foreach (Character candidate in _candidates)
			{
				if ((Object)(object)candidate == (Object)null || (Object)(object)candidate == (Object)(object)owner || candidate.IsDead() || !BaseAI.IsEnemy(owner, candidate))
				{
					continue;
				}
				Vector3 val = candidate.GetCenterPoint() - eyePoint;
				float magnitude = ((Vector3)(ref val)).magnitude;
				if (!(magnitude < 1f) && !(magnitude > 60f))
				{
					float num3 = Vector3.Dot(normalized, val / magnitude);
					if (!(num3 < 0.9063f) && (num3 > num + 0.002f || (num3 >= num - 0.002f && magnitude < num2)))
					{
						result = candidate;
						num = num3;
						num2 = magnitude;
					}
				}
			}
			_candidates.Clear();
			return result;
		}
	}
	[HarmonyPatch]
	internal static class GungnirImpactPatch
	{
		private static readonly FieldInfo OwnerField = typeof(Projectile).GetField("m_owner", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static MethodBase TargetMethod()
		{
			MethodInfo[] methods = typeof(Projectile).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (methodInfo.Name == "OnHit" && parameters.Length >= 3 && parameters[0].ParameterType == typeof(Collider))
				{
					return methodInfo;
				}
			}
			throw new MissingMethodException("Projectile.OnHit(Collider, ...) was not found.");
		}

		private static void Prefix(Projectile __instance, Collider collider, out bool __state)
		{
			__state = false;
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)collider == (Object)null) && !(OwnerField == null) && !((Object)(object)((Component)__instance).GetComponent<GungnirHoming>() == (Object)null))
			{
				Character componentInParent = ((Component)collider).GetComponentInParent<Character>();
				object? value = OwnerField.GetValue(__instance);
				Character val = (Character)((value is Character) ? value : null);
				__state = (Object)(object)componentInParent != (Object)null && (Object)(object)val != (Object)null && (Object)(object)componentInParent != (Object)(object)val && BaseAI.IsEnemy(val, componentInParent);
			}
		}

		private static void Postfix(Projectile __instance, bool __state)
		{
			if (__state && !((Object)(object)__instance == (Object)null) && !((Object)(object)ZNetScene.instance == (Object)null))
			{
				ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
				if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner())
				{
					ZNetScene.instance.Destroy(((Component)__instance).gameObject);
				}
			}
		}
	}
	internal static class GungnirPlugin
	{
		internal static void Register()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			try
			{
				ItemConfig val = new ItemConfig
				{
					Name = "Gungnir, Odin's Spear",
					Description = "Odin's unerring spear. With no shield equipped, block to summon six Einherjar for 50 Eitr. Throw with the usual secondary attack.",
					CraftingStation = "forge",
					MinStationLevel = 1
				};
				val.AddRequirement(new RequirementConfig("SpearGold", 1, 0, true));
				val.AddRequirement(new RequirementConfig("BlackMetal", 20, 0, true));
				val.AddRequirement(new RequirementConfig("YggdrasilWood", 10, 0, true));
				CustomItem val2 = new CustomItem("Gungnir", "SpearGold", val);
				ItemData itemData = val2.ItemDrop.m_itemData;
				itemData.m_shared = Copy<SharedData>(itemData.m_shared);
				SharedData shared = itemData.m_shared;
				shared.m_name = "$item_gungnir";
				shared.m_description = "$item_gungnir_description";
				if (shared.m_secondaryAttack == null)
				{
					throw new InvalidOperationException("The Nord Spear has no secondary throw attack.");
				}
				shared.m_secondaryAttack = Copy<Attack>(shared.m_secondaryAttack);
				Attack secondaryAttack = shared.m_secondaryAttack;
				if ((Object)(object)secondaryAttack.m_attackProjectile == (Object)null)
				{
					throw new InvalidOperationException("The Nord Spear has no throw projectile.");
				}
				secondaryAttack.m_consumeItem = false;
				GameObject val3 = PrefabManager.Instance.CreateClonedPrefab("Gungnir_Projectile", secondaryAttack.m_attackProjectile);
				if ((Object)(object)val3 == (Object)null)
				{
					throw new InvalidOperationException("Could not clone the Nord Spear projectile.");
				}
				Projectile component = val3.GetComponent<Projectile>();
				if ((Object)(object)component == (Object)null)
				{
					throw new InvalidOperationException("Nord Spear projectile has no Projectile component.");
				}
				SetRequired(component, "m_respawnItemOnHit", false);
				SetRequired(component, "m_stayAfterHitStatic", true);
				SetRequired(component, "m_stayAfterHitDynamic", true);
				SetRequired(component, "m_stayTTL", 5f);
				SetOptional(component, "m_spawnOnTtl", false);
				val3.AddComponent<GungnirHoming>();
				Blacken(val2.ItemPrefab);
				Blacken(val3);
				Sprite val4 = MakeBlackIcon(shared.m_icons);
				if ((Object)(object)val4 != (Object)null)
				{
					shared.m_icons = (Sprite[])(object)new Sprite[1] { val4 };
				}
				PrefabManager.Instance.AddPrefab(val3);
				secondaryAttack.m_attackProjectile = val3;
				ItemManager.Instance.AddItem(val2);
				try
				{
					GungnirSummon.Register(val2);
				}
				catch (Exception ex)
				{
					Debug.LogError((object)("[OdinRegalia] Gungnir spear registered, but summon registration failed: " + ex));
				}
				CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
				string text = "English";
				localization.AddTranslation(ref text, new Dictionary<string, string>
				{
					["item_gungnir"] = "Gungnir, Odin's Spear",
					["item_gungnir_description"] = "Odin's unerring spear. Without a shield, press block to summon six Einherjar for 50 Eitr. Use the usual secondary attack to throw it."
				});
				Debug.Log((object)"[OdinRegalia] Gungnir registered. Spawn for testing: spawn Gungnir 1");
			}
			catch (Exception ex2)
			{
				Debug.LogError((object)("[OdinRegalia] Could not register Gungnir: " + ex2));
			}
		}

		private static T Copy<T>(T value) where T : class
		{
			return (T)typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(value, null);
		}

		private static void SetRequired(object target, string name, object value)
		{
			FieldInfo field = target.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null || field.FieldType != value.GetType())
			{
				throw new MissingFieldException(target.GetType().FullName, name);
			}
			field.SetValue(target, value);
		}

		private static void SetOptional(object target, string name, object value)
		{
			FieldInfo field = target.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null && field.FieldType == value.GetType())
			{
				field.SetValue(target, value);
			}
		}

		private static void Blacken(GameObject root)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				Material[] sharedMaterials = val.sharedMaterials;
				Material[] array = (Material[])(object)new Material[sharedMaterials.Length];
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					if (!((Object)(object)sharedMaterials[j] == (Object)null))
					{
						Material val2 = new Material(sharedMaterials[j]);
						if (val2.HasProperty("_Color"))
						{
							val2.SetColor("_Color", new Color(0.035f, 0.037f, 0.045f, 1f));
						}
						if (val2.HasProperty("_BaseColor"))
						{
							val2.SetColor("_BaseColor", new Color(0.035f, 0.037f, 0.045f, 1f));
						}
						if (val2.HasProperty("_EmissionColor"))
						{
							val2.SetColor("_EmissionColor", Color.black);
						}
						array[j] = val2;
					}
				}
				val.sharedMaterials = array;
			}
		}

		private static Sprite MakeBlackIcon(Sprite[] source)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			if (source == null || source.Length == 0 || (Object)(object)source[0] == (Object)null)
			{
				return null;
			}
			try
			{
				Sprite obj = source[0];
				Texture2D texture = obj.texture;
				Rect textureRect = obj.textureRect;
				int num = Mathf.RoundToInt(((Rect)(ref textureRect)).width);
				int num2 = Mathf.RoundToInt(((Rect)(ref textureRect)).height);
				RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)0);
				RenderTexture active = RenderTexture.active;
				Texture2D val;
				try
				{
					Graphics.Blit((Texture)(object)texture, temporary);
					RenderTexture.active = temporary;
					val = new Texture2D(num, num2, (TextureFormat)4, false);
					val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0);
					val.Apply();
				}
				finally
				{
					RenderTexture.active = active;
					RenderTexture.ReleaseTemporary(temporary);
				}
				Color[] pixels = val.GetPixels();
				for (int i = 0; i < pixels.Length; i++)
				{
					float grayscale = ((Color)(ref pixels[i])).grayscale;
					pixels[i] = new Color(0.018f + grayscale * 0.13f, 0.019f + grayscale * 0.14f, 0.026f + grayscale * 0.16f, pixels[i].a);
				}
				val.SetPixels(pixels);
				val.Apply();
				((Object)val).name = "Gungnir_Icon";
				return Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num2), new Vector2(0.5f, 0.5f));
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[OdinRegalia] Could not tint Gungnir icon: " + ex.Message));
				return null;
			}
		}
	}
	internal static class GungnirSummon
	{
		private const int EinherjarPerCast = 6;

		internal static Attack CastAttack { get; private set; }

		internal static void Register(CustomItem spear)
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab("StaffSkeleton");
			GameObject prefab2 = PrefabManager.Instance.GetPrefab("StaffShield");
			if ((Object)(object)prefab == (Object)null || (Object)(object)prefab2 == (Object)null)
			{
				throw new InvalidOperationException("StaffSkeleton or StaffShield is unavailable");
			}
			Attack attack = prefab.GetComponent<ItemDrop>().m_itemData.m_shared.m_attack;
			Attack attack2 = prefab2.GetComponent<ItemDrop>().m_itemData.m_shared.m_attack;
			if (attack == null || attack2 == null || (Object)(object)attack.m_attackProjectile == (Object)null)
			{
				throw new InvalidOperationException("Vanilla summon or shield casting attack is unavailable");
			}
			GameObject val = MakeSoldier();
			PrefabManager.Instance.AddPrefab(val);
			GameObject val2 = PrefabManager.Instance.CreateClonedPrefab("OdinSoldier_Spawn", attack.m_attackProjectile);
			SpawnAbility val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<SpawnAbility>() : null);
			if ((Object)(object)val3 == (Object)null)
			{
				throw new InvalidOperationException("Dead Raiser projectile lacks SpawnAbility");
			}
			val3.m_spawnPrefab = (GameObject[])(object)new GameObject[1] { val };
			val3.m_minToSpawn = 6;
			FieldInfo fieldInfo = FindField(((object)val3).GetType(), "m_maxToSpawn");
			if (fieldInfo != null && fieldInfo.FieldType == typeof(int))
			{
				fieldInfo.SetValue(val3, 6);
			}
			SetRequiredField(val3, "m_setMaxInstancesFromWeaponLevel", false);
			SetSummonLimit(val3, 6);
			PrefabManager.Instance.AddPrefab(val2);
			CastAttack = ShallowCopy<Attack>(attack);
			CastAttack.m_attackProjectile = val2;
			CastAttack.m_attackAnimation = attack2.m_attackAnimation;
			CastAttack.m_attackEitr = 50f;
			CastAttack.m_attackStamina = 0f;
			CastAttack.m_attackHealth = 0f;
			CastAttack.m_attackHealthPercentage = 0f;
			CastAttack.m_consumeItem = false;
			Debug.Log((object)"[OdinRegalia] Summon registered: 6 Einherjar, 50 Eitr, StaffShield animation");
		}

		private static GameObject MakeSoldier()
		{
			GameObject prefab = PrefabManager.Instance.GetPrefab("Player");
			GameObject val = (((Object)(object)prefab != (Object)null) ? PrefabManager.Instance.CreateClonedPrefab("OdinSoldier", prefab) : null);
			GameObject prefab2 = PrefabManager.Instance.GetPrefab("Skeleton_Friendly");
			if ((Object)(object)val == (Object)null || (Object)(object)prefab2 == (Object)null)
			{
				throw new InvalidOperationException("Player or Skeleton_Friendly prefab is unavailable");
			}
			Player component = val.GetComponent<Player>();
			if ((Object)(object)component == (Object)null)
			{
				throw new InvalidOperationException("Player prefab lacks Player component");
			}
			Dictionary<FieldInfo, object> values = Snapshot(component, typeof(Humanoid));
			Component component2 = val.GetComponent("PlayerController");
			if ((Object)(object)component2 != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component2);
			}
			Component component3 = val.GetComponent("Talker");
			if ((Object)(object)component3 != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component3);
			}
			Object.DestroyImmediate((Object)(object)component);
			Humanoid val2 = val.AddComponent<Humanoid>();
			Restore(val2, values);
			FieldInfo fieldInfo = FindField(((object)val2).GetType(), "m_tamed");
			if (fieldInfo != null && fieldInfo.FieldType == typeof(bool))
			{
				fieldInfo.SetValue(val2, true);
			}
			val.tag = "Untagged";
			MonsterAI component4 = prefab2.GetComponent<MonsterAI>();
			if ((Object)(object)component4 == (Object)null)
			{
				throw new InvalidOperationException("Friendly skeleton lacks MonsterAI");
			}
			MonsterAI target = val.AddComponent<MonsterAI>();
			CopySettings(component4, target);
			Tameable component5 = prefab2.GetComponent<Tameable>();
			if ((Object)(object)component5 != (Object)null)
			{
				Tameable target2 = val.AddComponent<Tameable>();
				CopySettings(component5, target2);
				GameObject prefab3 = PrefabManager.Instance.GetPrefab("OdinChest");
				GameObject prefab4 = PrefabManager.Instance.GetPrefab("OdinLegs");
				GameObject prefab5 = PrefabManager.Instance.GetPrefab("AxeGold");
				if ((Object)(object)prefab3 == (Object)null || (Object)(object)prefab4 == (Object)null || (Object)(object)prefab5 == (Object)null)
				{
					throw new InvalidOperationException("Soldier equipment missing: OdinChest, OdinLegs or AxeGold");
				}
				val2.m_defaultItems = (GameObject[])(object)new GameObject[3] { prefab3, prefab4, prefab5 };
				((Character)val2).m_name = "Einherjar";
				return val;
			}
			throw new InvalidOperationException("Friendly skeleton lacks Tameable");
		}

		private static Dictionary<FieldInfo, object> Snapshot(object source, Type from)
		{
			Dictionary<FieldInfo, object> dictionary = new Dictionary<FieldInfo, object>();
			Type type = from;
			while (type != null && type != typeof(MonoBehaviour))
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (!fieldInfo.IsStatic && !fieldInfo.IsInitOnly)
					{
						dictionary[fieldInfo] = fieldInfo.GetValue(source);
					}
				}
				type = type.BaseType;
			}
			return dictionary;
		}

		private static void Restore(object target, Dictionary<FieldInfo, object> values)
		{
			foreach (KeyValuePair<FieldInfo, object> value in values)
			{
				value.Key.SetValue(target, value.Value);
			}
		}

		private static void CopySettings(object source, object target)
		{
			Type type = source.GetType();
			while (type != null && type != typeof(MonoBehaviour))
			{
				FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				foreach (FieldInfo fieldInfo in fields)
				{
					if (!fieldInfo.IsStatic && !fieldInfo.IsInitOnly)
					{
						Type fieldType = fieldInfo.FieldType;
						if (fieldType.IsPrimitive || fieldType.IsEnum || fieldType == typeof(string) || fieldType == typeof(Vector3))
						{
							fieldInfo.SetValue(target, fieldInfo.GetValue(source));
						}
					}
				}
				type = type.BaseType;
			}
		}

		private static T ShallowCopy<T>(T value) where T : class
		{
			return (T)typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(value, null);
		}

		private static void SetSummonLimit(SpawnAbility spawn, int limit)
		{
			FieldInfo fieldInfo = FindField(((object)spawn).GetType(), "m_levelUpSettings");
			IList list = ((fieldInfo != null) ? (fieldInfo.GetValue(spawn) as IList) : null);
			if (list == null || list.Count == 0)
			{
				throw new InvalidOperationException("Dead Raiser has no summon level settings");
			}
			if (!(Activator.CreateInstance(fieldInfo.FieldType) is IList list2))
			{
				throw new InvalidOperationException("Cannot clone summon level settings");
			}
			foreach (object item in list)
			{
				object obj = CloneEntry(item);
				SetRequiredNumber(obj, "m_maxSpawns", limit);
				list2.Add(obj);
			}
			object obj2 = CloneEntry(list[0]);
			SetRequiredNumber(obj2, "m_skillLevel", 0);
			SetRequiredNumber(obj2, "m_maxSpawns", limit);
			list2.Insert(0, obj2);
			fieldInfo.SetValue(spawn, list2);
		}

		private static object CloneEntry(object source)
		{
			if (source == null)
			{
				throw new InvalidOperationException("Summon level setting was null");
			}
			if (source.GetType().IsValueType)
			{
				return source;
			}
			return typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(source, null);
		}

		private static void SetRequiredField(object target, string name, object value)
		{
			FieldInfo fieldInfo = FindField(target.GetType(), name);
			if (fieldInfo == null || fieldInfo.FieldType != value.GetType())
			{
				throw new MissingFieldException(target.GetType().FullName, name);
			}
			fieldInfo.SetValue(target, value);
		}

		private static void SetRequiredNumber(object target, string name, int value)
		{
			FieldInfo fieldInfo = FindField(target.GetType(), name);
			if (fieldInfo == null || !typeof(IConvertible).IsAssignableFrom(fieldInfo.FieldType))
			{
				throw new MissingFieldException(target.GetType().FullName, name);
			}
			fieldInfo.SetValue(target, Convert.ChangeType(value, fieldInfo.FieldType));
		}

		private static FieldInfo FindField(Type targetType, string name)
		{
			Type type = targetType;
			while (type != null)
			{
				FieldInfo field = type.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null)
				{
					return field;
				}
				type = type.BaseType;
			}
			return null;
		}
	}
	[HarmonyPatch]
	internal static class GungnirSummonInput
	{
		private static readonly FieldInfo LeftHand = typeof(Humanoid).GetField("m_leftItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

		private static MethodBase TargetMethod()
		{
			MethodInfo[] methods = typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name != "SetControls")
				{
					continue;
				}
				bool flag = false;
				bool flag2 = false;
				ParameterInfo[] parameters = methodInfo.GetParameters();
				foreach (ParameterInfo parameterInfo in parameters)
				{
					if (parameterInfo.Name == "block" && parameterInfo.ParameterType == typeof(bool))
					{
						flag = true;
					}
					if (parameterInfo.Name == "blockHold" && parameterInfo.ParameterType == typeof(bool))
					{
						flag2 = true;
					}
				}
				if (flag && flag2)
				{
					return methodInfo;
				}
			}
			throw new MissingMethodException("Player.SetControls(... block, blockHold ...)");
		}

		private static void Prefix(Player __instance, ref bool block, ref bool blockHold, ref bool secondaryAttack, ref bool secondaryAttackHold)
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Invalid comparison between Unknown and I4
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || GungnirSummon.CastAttack == null)
			{
				return;
			}
			ItemData currentWeapon = ((Humanoid)__instance).GetCurrentWeapon();
			if (currentWeapon == null || currentWeapon.m_shared == null || currentWeapon.m_shared.m_name != "$item_gungnir")
			{
				return;
			}
			ItemData val = (ItemData)((LeftHand != null) ? /*isinst with value type is only supported in some contexts*/: null);
			if (val != null && val.m_shared != null && (int)val.m_shared.m_itemType == 5)
			{
				return;
			}
			bool flag = block;
			if (flag)
			{
				Attack secondaryAttack2 = currentWeapon.m_shared.m_secondaryAttack;
				try
				{
					currentWeapon.m_shared.m_secondaryAttack = GungnirSummon.CastAttack;
					((Character)__instance).StartAttack((Character)null, true);
				}
				catch (Exception ex)
				{
					Debug.LogError((object)("[OdinRegalia] Summon cast failed: " + ex));
				}
				finally
				{
					currentWeapon.m_shared.m_secondaryAttack = secondaryAttack2;
				}
			}
			block = false;
			blockHold = false;
			if (flag & secondaryAttack)
			{
				secondaryAttack = false;
				secondaryAttackHold = false;
			}
		}
	}
}