Decompiled source of RootboundWitch v1.3.1

plugins/ADARC-RootboundWitch/ADARC.RootboundWitch.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using SoftReferenceableAssets;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Rootbound Witch")]
[assembly: AssemblyDescription("A restriction-led moss witch transformation for Valheim.")]
[assembly: AssemblyCompany("ADARC")]
[assembly: AssemblyProduct("Rootbound Witch")]
[assembly: ComVisible(false)]
[assembly: Guid("6e7899d2-9912-4d93-956b-6ead18e4fd18")]
[assembly: AssemblyFileVersion("1.3.1.0")]
[assembly: AssemblyVersion("1.3.1.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 ADARC.RootboundWitch
{
	internal static class BogWitchBackGrowth
	{
		private sealed class GrowthInstance
		{
			internal Player Owner;

			internal GameObject Upper;

			internal GameObject Lower;

			internal bool MaterialStateKnown;

			internal int LastMaterialState;

			internal bool IsValid
			{
				get
				{
					if ((Object)(object)Owner != (Object)null && Object.op_Implicit((Object)(object)Upper))
					{
						return Object.op_Implicit((Object)(object)Lower);
					}
					return false;
				}
			}
		}

		private static readonly string[] GrowthTokens = new string[8] { "branch", "root", "twig", "bark", "vine", "growth", "wood", "stick" };

		private static GameObject _upperTemplate;

		private static GameObject _lowerTemplate;

		private static readonly Dictionary<Player, GrowthInstance> Instances = new Dictionary<Player, GrowthInstance>();

		private static Bounds _combinedBounds;

		private static Material[] _ordinaryMaterials;

		private static Material[] _charredMaterials;

		private static Material[] _permafrostMaterials;

		private static float _nextResolveAt;

		private static bool _loggedFailure;

		internal static void Prepare()
		{
			//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_02c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02df: Expected O, but got Unknown
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)_upperTemplate) || Time.realtimeSinceStartup < _nextResolveAt)
			{
				return;
			}
			_nextResolveAt = Time.realtimeSinceStartup + 5f;
			GameObject val = RootboundContent.FindPrefab("BogWitch");
			if (!Object.op_Implicit((Object)(object)val))
			{
				if (!_loggedFailure)
				{
					RootboundWitchPlugin.Log.LogWarning((object)"Bog Witch back-growth experiment is waiting for the live BogWitch prefab.");
					_loggedFailure = true;
				}
				return;
			}
			try
			{
				List<CombineInstance> list = new List<CombineInstance>();
				List<Material> list2 = new List<Material>();
				List<string> list3 = new List<string>();
				List<string> list4 = new List<string>();
				Matrix4x4 worldToLocalMatrix = val.transform.worldToLocalMatrix;
				Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val2 in componentsInChildren)
				{
					Mesh val3 = SourceMesh(val2);
					if (!Object.op_Implicit((Object)(object)val3) || val3.subMeshCount <= 0)
					{
						continue;
					}
					Material[] array = (Material[])(((object)val2.sharedMaterials) ?? ((object)new Material[0]));
					string text = RelativePath(((Component)val2).transform, val.transform);
					bool flag = ContainsGrowthToken(((Object)val2).name);
					list4.Add(text + " :: " + string.Join(", ", from material in array
						where Object.op_Implicit((Object)(object)material)
						select ((Object)material).name));
					for (int num = 0; num < val3.subMeshCount; num++)
					{
						Material val4 = ((array.Length == 0) ? null : array[Math.Min(num, array.Length - 1)]);
						string text2 = ((Object.op_Implicit((Object)(object)val4) && Object.op_Implicit((Object)(object)val4.mainTexture)) ? ((Object)val4.mainTexture).name : string.Empty);
						string identity = (Object.op_Implicit((Object)(object)val4) ? ((Object)val4).name : string.Empty) + " " + text2;
						if (flag || ContainsGrowthToken(identity))
						{
							CombineInstance item = default(CombineInstance);
							((CombineInstance)(ref item)).mesh = val3;
							((CombineInstance)(ref item)).subMeshIndex = num;
							((CombineInstance)(ref item)).transform = worldToLocalMatrix * ((Component)val2).transform.localToWorldMatrix;
							list.Add(item);
							list2.Add(val4);
							list3.Add(text + "[" + num + "] / " + (Object.op_Implicit((Object)(object)val4) ? ((Object)val4).name : "<no material>"));
						}
					}
				}
				if (list.Count == 0)
				{
					if (!_loggedFailure)
					{
						RootboundWitchPlugin.Log.LogWarning((object)("Bog Witch branch extraction found no named growth geometry. Live renderer inventory: " + string.Join(" | ", list4)));
						_loggedFailure = true;
					}
					return;
				}
				Mesh val5 = new Mesh
				{
					name = "Rootbound_BogWitchBranchCrownMesh",
					indexFormat = (IndexFormat)1
				};
				val5.CombineMeshes(list.ToArray(), false, true, false);
				val5.RecalculateBounds();
				_combinedBounds = val5.bounds;
				Bounds bounds = val5.bounds;
				float y = ((Bounds)(ref bounds)).min.y;
				bounds = val5.bounds;
				float splitY = y + ((Bounds)(ref bounds)).size.y * 0.38f;
				Mesh mesh = SplitMesh(val5, splitY, lower: false);
				Mesh mesh2 = SplitMesh(val5, splitY, lower: true);
				PullCentralSpineBranchesForward(mesh);
				LiftDetachedCentralLowerBranch(mesh2);
				_ordinaryMaterials = list2.ToArray();
				_charredMaterials = RootboundAshlandsVisuals.BuildExternalCharredMaterials(_ordinaryMaterials);
				_permafrostMaterials = PermafrostVisuals.BuildExternalWhiteMaterials(_ordinaryMaterials);
				_upperTemplate = CreateTemplate("Rootbound_BogWitchBranchCrownUpperTemplate", mesh);
				_lowerTemplate = CreateTemplate("Rootbound_BogWitchBranchCrownLowerTemplate", mesh2);
				_loggedFailure = false;
				RootboundWitchPlugin.Log.LogInfo((object)("Bog Witch back-growth extracted " + list.Count + " exact branch submeshes: " + string.Join(" | ", list3)));
			}
			catch (Exception ex)
			{
				if (!_loggedFailure)
				{
					RootboundWitchPlugin.Log.LogWarning((object)("Bog Witch branch-only extraction failed safely; gameplay content remains intact: " + ex.GetBaseException().Message));
					_loggedFailure = true;
				}
			}
		}

		internal static void Update(Player player, bool active)
		{
			if (!RootboundWitchPlugin.EnableBogWitchBackGrowth.Value)
			{
				ClearInstances();
				return;
			}
			if (!Object.op_Implicit((Object)(object)_upperTemplate) || !Object.op_Implicit((Object)(object)_lowerTemplate))
			{
				Prepare();
				if (!Object.op_Implicit((Object)(object)_upperTemplate) || !Object.op_Implicit((Object)(object)_lowerTemplate))
				{
					return;
				}
			}
			HashSet<Player> currentPlayers = new HashSet<Player>();
			foreach (Player item in from candidate in Player.GetAllPlayers()
				where (Object)(object)candidate != (Object)null
				select candidate)
			{
				currentPlayers.Add(item);
				int num = ((!((Object)(object)item == (Object)(object)player)) ? RootboundNetworkState.GetVisualState(item) : (active ? RootboundState.GrowthCrownVisualState(item) : 0));
				if (num <= 0)
				{
					RemoveInstance(item);
					continue;
				}
				if (!Instances.TryGetValue(item, out var value) || !value.IsValid)
				{
					RemoveInstance(item);
					value = new GrowthInstance
					{
						Owner = item,
						Upper = CreateInstance(_upperTemplate, "Rootbound_BogWitchBranchCrownUpper", item),
						Lower = CreateInstance(_lowerTemplate, "Rootbound_BogWitchBranchCrownLower", item)
					};
					AttachToAnimatedTorso(value.Upper, item, lower: false);
					AttachToAnimatedTorso(value.Lower, item, lower: true);
					value.Upper.SetActive(true);
					value.Lower.SetActive(true);
					Instances[item] = value;
				}
				if (!value.MaterialStateKnown || value.LastMaterialState != num)
				{
					Material[] materials = ((num >= 3) ? _permafrostMaterials : ((num == 2) ? _charredMaterials : _ordinaryMaterials));
					ApplyMaterials(value.Upper, materials);
					ApplyMaterials(value.Lower, materials);
					value.LastMaterialState = num;
					value.MaterialStateKnown = true;
				}
			}
			Player[] array = Instances.Keys.Where((Player existing) => (Object)(object)existing == (Object)null || !currentPlayers.Contains(existing)).ToArray();
			for (int num2 = 0; num2 < array.Length; num2++)
			{
				RemoveInstance(array[num2]);
			}
		}

		internal static void Clear()
		{
			ClearInstances();
			if (Object.op_Implicit((Object)(object)_upperTemplate))
			{
				Object.Destroy((Object)(object)_upperTemplate);
			}
			if (Object.op_Implicit((Object)(object)_lowerTemplate))
			{
				Object.Destroy((Object)(object)_lowerTemplate);
			}
			_upperTemplate = null;
			_lowerTemplate = null;
			_ordinaryMaterials = null;
			_charredMaterials = null;
			_permafrostMaterials = null;
		}

		private static void ClearInstances()
		{
			GrowthInstance[] array = Instances.Values.ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				DestroyInstance(array[i]);
			}
			Instances.Clear();
		}

		private static void RemoveInstance(Player player)
		{
			if (player != null && Instances.TryGetValue(player, out var value))
			{
				DestroyInstance(value);
				Instances.Remove(player);
			}
		}

		private static void DestroyInstance(GrowthInstance instance)
		{
			if (instance != null)
			{
				if (Object.op_Implicit((Object)(object)instance.Upper))
				{
					Object.Destroy((Object)(object)instance.Upper);
				}
				if (Object.op_Implicit((Object)(object)instance.Lower))
				{
					Object.Destroy((Object)(object)instance.Lower);
				}
			}
		}

		private static GameObject CreateInstance(GameObject template, string name, Player player)
		{
			GameObject obj = Object.Instantiate<GameObject>(template, ((Component)player).transform, false);
			((Object)obj).name = name;
			((Object)obj).hideFlags = (HideFlags)52;
			PositionOnBack(obj, CurrentStatureFactor(player));
			return obj;
		}

		private static void PositionOnBack(GameObject crown, float statureFactor)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: 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_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			Vector3 size = ((Bounds)(ref _combinedBounds)).size;
			Bounds val = (Bounds)((((Vector3)(ref size)).sqrMagnitude > 0f) ? _combinedBounds : new Bounds(Vector3.zero, Vector3.one));
			float num = Mathf.Max(0.5f, RootboundWitchPlugin.BogWitchGrowthWidth.Value);
			float num2 = Mathf.Max(0.5f, RootboundWitchPlugin.BogWitchGrowthHeight.Value);
			float num3 = Mathf.Min(num / Mathf.Max(0.05f, ((Bounds)(ref val)).size.x), num2 / Mathf.Max(0.05f, ((Bounds)(ref val)).size.y));
			num3 = Mathf.Clamp(num3, 0.05f, 12f);
			crown.transform.localRotation = Quaternion.identity;
			statureFactor = Mathf.Clamp(statureFactor, 0.55f, 1f);
			crown.transform.localScale = Vector3.one * num3 * statureFactor;
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(0f, RootboundWitchPlugin.BogWitchGrowthVerticalOffset.Value, RootboundWitchPlugin.BogWitchGrowthBackOffset.Value);
			crown.transform.localPosition = (val2 - ((Bounds)(ref val)).center * num3) * statureFactor;
		}

		private static void AttachToAnimatedTorso(GameObject crown, Player player, bool lower)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			Transform val = (lower ? FindLowerBackAttachment(player) : FindBackAttachment(player));
			if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val == (Object)(object)((Component)player).transform)
			{
				RootboundWitchPlugin.Log.LogWarning((object)"Bog Witch branch crown found no animated torso anchor; retaining player-root attachment.");
				return;
			}
			if (lower)
			{
				Transform transform = crown.transform;
				transform.position += ((Component)player).transform.forward * (0.11f * CurrentStatureFactor(player));
			}
			else
			{
				Transform transform2 = crown.transform;
				transform2.position += ((Component)player).transform.forward * (0.065f * CurrentStatureFactor(player));
			}
			crown.transform.SetParent(val, true);
			RootboundWitchPlugin.Log.LogInfo((object)("Bog Witch branch crown " + (lower ? "lower" : "upper") + " section bound to animated anchor: " + HierarchyPath(val, ((Component)player).transform)));
		}

		private static float CurrentStatureFactor(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return 1f;
			}
			if (!(((Object)(object)player == (Object)(object)Player.m_localPlayer) ? RootboundState.IsFullSet(player) : (RootboundNetworkState.GetSupportTier(player) > 0)))
			{
				return 1f;
			}
			return Mathf.Clamp(RootboundWitchPlugin.FullSetVisualScale.Value, 0.55f, 1f);
		}

		private static Transform FindLowerBackAttachment(Player player)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			Animator val = ((IEnumerable<Animator>)((Component)player).GetComponentsInChildren<Animator>(true)).FirstOrDefault((Func<Animator, bool>)((Animator candidate) => Object.op_Implicit((Object)(object)candidate) && candidate.isHuman));
			if (Object.op_Implicit((Object)(object)val))
			{
				HumanBodyBones[] array = (HumanBodyBones[])(object)new HumanBodyBones[2]
				{
					default(HumanBodyBones),
					(HumanBodyBones)7
				};
				foreach (HumanBodyBones val2 in array)
				{
					Transform boneTransform = val.GetBoneTransform(val2);
					if (Object.op_Implicit((Object)(object)boneTransform))
					{
						return boneTransform;
					}
				}
			}
			Transform[] componentsInChildren = ((Component)player).GetComponentsInChildren<Transform>(true);
			string[] array2 = new string[5] { "pelvis", "hips", "hip", "spine1", "spine" };
			foreach (string token in array2)
			{
				Transform val3 = ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform transform) => Normalize(((Object)transform).name).Contains(token)));
				if (Object.op_Implicit((Object)(object)val3))
				{
					return val3;
				}
			}
			return ((Component)player).transform;
		}

		private static GameObject CreateTemplate(string name, Mesh mesh)
		{
			//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_000d: 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_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			GameObject val = new GameObject(name);
			val.SetActive(false);
			((Object)val).hideFlags = (HideFlags)61;
			MeshFilter val2 = val.AddComponent<MeshFilter>();
			MeshRenderer obj = val.AddComponent<MeshRenderer>();
			val2.sharedMesh = mesh;
			((Renderer)obj).sharedMaterials = _ordinaryMaterials;
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)1;
			((Renderer)obj).receiveShadows = true;
			return val;
		}

		private static void ApplyMaterials(GameObject instance, Material[] materials)
		{
			if (Object.op_Implicit((Object)(object)instance))
			{
				MeshRenderer component = instance.GetComponent<MeshRenderer>();
				if (Object.op_Implicit((Object)(object)component))
				{
					((Renderer)component).sharedMaterials = materials;
				}
			}
		}

		private static Mesh SplitMesh(Mesh source, float splitY, bool lower)
		{
			//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_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			Mesh val = new Mesh
			{
				name = ((Object)source).name + (lower ? "_Lower" : "_Upper"),
				indexFormat = source.indexFormat,
				vertices = source.vertices,
				normals = source.normals,
				tangents = source.tangents,
				colors32 = source.colors32,
				uv = source.uv,
				uv2 = source.uv2,
				uv3 = source.uv3,
				uv4 = source.uv4,
				subMeshCount = source.subMeshCount
			};
			Vector3[] vertices = source.vertices;
			int num = 0;
			for (int i = 0; i < source.subMeshCount; i++)
			{
				int[] triangles = source.GetTriangles(i);
				List<int> list = new List<int>(triangles.Length);
				for (int j = 0; j + 2 < triangles.Length; j += 3)
				{
					float num2 = (vertices[triangles[j]].y + vertices[triangles[j + 1]].y + vertices[triangles[j + 2]].y) / 3f;
					if (lower ? (num2 <= splitY) : (num2 > splitY))
					{
						list.Add(triangles[j]);
						list.Add(triangles[j + 1]);
						list.Add(triangles[j + 2]);
						num++;
					}
				}
				val.SetTriangles(list, i, false);
			}
			if (num == 0)
			{
				Object.Destroy((Object)(object)val);
				throw new InvalidOperationException("Bog Witch branch crown split produced an empty " + (lower ? "lower" : "upper") + " section.");
			}
			val.RecalculateBounds();
			return val;
		}

		private static void LiftDetachedCentralLowerBranch(Mesh mesh)
		{
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01af: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f6: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)mesh) || mesh.vertexCount == 0)
			{
				return;
			}
			Vector3[] vertices = mesh.vertices;
			int[] array = Enumerable.Repeat(-1, vertices.Length).ToArray();
			for (int i = 0; i < mesh.subMeshCount; i++)
			{
				int[] triangles = mesh.GetTriangles(i);
				for (int j = 0; j + 2 < triangles.Length; j += 3)
				{
					int num = triangles[j];
					int num2 = triangles[j + 1];
					int num3 = triangles[j + 2];
					Activate(array, num);
					Activate(array, num2);
					Activate(array, num3);
					Union(array, num, num2);
					Union(array, num2, num3);
				}
			}
			Dictionary<int, List<int>> dictionary = new Dictionary<int, List<int>>();
			for (int k = 0; k < array.Length; k++)
			{
				if (array[k] >= 0)
				{
					int key = Find(array, k);
					if (!dictionary.TryGetValue(key, out var value))
					{
						value = (dictionary[key] = new List<int>());
					}
					value.Add(k);
				}
			}
			if (dictionary.Count < 2)
			{
				RootboundWitchPlugin.Log.LogWarning((object)"Bog Witch lower crown had no separable central branch; leaving its mesh unchanged.");
				return;
			}
			Bounds val = BoundsFor(vertices, dictionary.Values.SelectMany((List<int> result) => result));
			float num4 = Mathf.Max(0.01f, ((Bounds)(ref val)).size.x);
			float num5 = Mathf.Max(0.01f, ((Bounds)(ref val)).size.y);
			List<int> list2 = null;
			Bounds val2 = default(Bounds);
			float num6 = float.MaxValue;
			foreach (List<int> value2 in dictionary.Values)
			{
				if (value2.Count < 6)
				{
					continue;
				}
				Bounds val3 = BoundsFor(vertices, value2);
				float num7 = Mathf.Abs(((Bounds)(ref val3)).center.x - ((Bounds)(ref val)).center.x) / num4;
				float num8 = (((Bounds)(ref val3)).center.y - ((Bounds)(ref val)).min.y) / num5;
				float num9 = ((Bounds)(ref val3)).size.y / num5;
				if (!(num7 > 0.24f) && !(num8 > 0.64f) && !(num9 < 0.12f))
				{
					float num10 = num7 * 2f + num8 - num9 * 0.15f;
					if (num10 < num6)
					{
						num6 = num10;
						list2 = value2;
						val2 = val3;
					}
				}
			}
			if (list2 == null)
			{
				RootboundWitchPlugin.Log.LogWarning((object)"Bog Witch lower crown found no safe central dangling component to lift.");
				return;
			}
			float num11 = CrownBaseScale();
			float num12 = 0.18f / Mathf.Max(0.01f, num11);
			foreach (int item in list2)
			{
				vertices[item].y += num12;
			}
			mesh.vertices = vertices;
			mesh.RecalculateBounds();
			RootboundWitchPlugin.Log.LogInfo((object)("Bog Witch central lower branch lifted by 0.18m at full stature (component center " + ((object)((Bounds)(ref val2)).center/*cast due to .constrained prefix*/).ToString() + ", vertices " + list2.Count + ")."));
		}

		private static void PullCentralSpineBranchesForward(Mesh mesh)
		{
			//IL_0149: 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)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)mesh) || mesh.vertexCount == 0)
			{
				return;
			}
			Vector3[] vertices = mesh.vertices;
			int[] array = Enumerable.Repeat(-1, vertices.Length).ToArray();
			for (int i = 0; i < mesh.subMeshCount; i++)
			{
				int[] triangles = mesh.GetTriangles(i);
				for (int j = 0; j + 2 < triangles.Length; j += 3)
				{
					int num = triangles[j];
					int num2 = triangles[j + 1];
					int num3 = triangles[j + 2];
					Activate(array, num);
					Activate(array, num2);
					Activate(array, num3);
					Union(array, num, num2);
					Union(array, num2, num3);
				}
			}
			Dictionary<int, List<int>> dictionary = new Dictionary<int, List<int>>();
			for (int k = 0; k < array.Length; k++)
			{
				if (array[k] >= 0)
				{
					int key = Find(array, k);
					if (!dictionary.TryGetValue(key, out var value))
					{
						value = (dictionary[key] = new List<int>());
					}
					value.Add(k);
				}
			}
			if (dictionary.Count < 3)
			{
				RootboundWitchPlugin.Log.LogWarning((object)"Bog Witch upper crown exposed fewer than three separable spine branches; retaining its accepted fit.");
				return;
			}
			Bounds usedBounds = BoundsFor(vertices, dictionary.Values.SelectMany((List<int> result) => result));
			float width = Mathf.Max(0.01f, ((Bounds)(ref usedBounds)).size.x);
			float height = Mathf.Max(0.01f, ((Bounds)(ref usedBounds)).size.y);
			List<List<int>> list2 = (from component in (from component in dictionary.Values
					where component.Count >= 6
					select new
					{
						Vertices = component,
						Bounds = BoundsFor(vertices, component)
					}).Where(component =>
				{
					//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_0009: 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_0038: 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_0040: Unknown result type (might be due to invalid IL or missing references)
					//IL_0050: Unknown result type (might be due to invalid IL or missing references)
					//IL_006a: Unknown result type (might be due to invalid IL or missing references)
					//IL_006f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0072: Unknown result type (might be due to invalid IL or missing references)
					Bounds bounds = component.Bounds;
					if (Mathf.Abs(((Bounds)(ref bounds)).center.x - ((Bounds)(ref usedBounds)).center.x) / width <= 0.22f)
					{
						bounds = component.Bounds;
						if ((((Bounds)(ref bounds)).min.y - ((Bounds)(ref usedBounds)).min.y) / height <= 0.28f)
						{
							bounds = component.Bounds;
							return ((Bounds)(ref bounds)).size.y / height >= 0.14f;
						}
					}
					return false;
				}).OrderBy(component =>
				{
					//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_0009: 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_0037: Unknown result type (might be due to invalid IL or missing references)
					//IL_003c: Unknown result type (might be due to invalid IL or missing references)
					//IL_003f: Unknown result type (might be due to invalid IL or missing references)
					//IL_004f: Unknown result type (might be due to invalid IL or missing references)
					Bounds bounds = component.Bounds;
					float num6 = Mathf.Abs(((Bounds)(ref bounds)).center.x - ((Bounds)(ref usedBounds)).center.x) / width * 2f;
					bounds = component.Bounds;
					return num6 + (((Bounds)(ref bounds)).min.y - ((Bounds)(ref usedBounds)).min.y) / height;
				}).Take(3)
				select component.Vertices).ToList();
			if (list2.Count != 3)
			{
				RootboundWitchPlugin.Log.LogWarning((object)"Bog Witch upper crown could not safely identify exactly three spine branches; moved none.");
				return;
			}
			float num4 = 0.085f / Mathf.Max(0.01f, CrownBaseScale());
			HashSet<int> hashSet = new HashSet<int>();
			foreach (List<int> item in list2)
			{
				foreach (int item2 in item)
				{
					if (hashSet.Add(item2))
					{
						vertices[item2].z += num4;
					}
				}
			}
			float num5 = 0.13f / Mathf.Max(0.01f, CrownBaseScale());
			foreach (List<int> item3 in list2.OrderBy(delegate(List<int> component)
			{
				//IL_0007: 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_000f: Unknown result type (might be due to invalid IL or missing references)
				Bounds val = BoundsFor(vertices, component);
				return ((Bounds)(ref val)).center.y;
			}).Take(2))
			{
				foreach (int item4 in item3)
				{
					vertices[item4].z += num5;
				}
			}
			mesh.vertices = vertices;
			mesh.RecalculateBounds();
			RootboundWitchPlugin.Log.LogInfo((object)"Bog Witch upper crown seated three central spine branches 0.085m forward; the two kidney-height roots received a further 0.13m lumbar seat.");
		}

		private static float CrownBaseScale()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			Vector3 size = ((Bounds)(ref _combinedBounds)).size;
			Bounds val = (Bounds)((((Vector3)(ref size)).sqrMagnitude > 0f) ? _combinedBounds : new Bounds(Vector3.zero, Vector3.one));
			return Mathf.Clamp(Mathf.Min(Mathf.Max(0.5f, RootboundWitchPlugin.BogWitchGrowthWidth.Value) / Mathf.Max(0.05f, ((Bounds)(ref val)).size.x), Mathf.Max(0.5f, RootboundWitchPlugin.BogWitchGrowthHeight.Value) / Mathf.Max(0.05f, ((Bounds)(ref val)).size.y)), 0.05f, 12f);
		}

		private static Bounds BoundsFor(Vector3[] vertices, IEnumerable<int> indices)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			Bounds result = default(Bounds);
			foreach (int index in indices)
			{
				if (!flag)
				{
					result = new Bounds(vertices[index], Vector3.zero);
					flag = true;
				}
				else
				{
					((Bounds)(ref result)).Encapsulate(vertices[index]);
				}
			}
			return result;
		}

		private static void Activate(int[] parent, int vertex)
		{
			if (vertex >= 0 && vertex < parent.Length && parent[vertex] < 0)
			{
				parent[vertex] = vertex;
			}
		}

		private static int Find(int[] parent, int vertex)
		{
			while (parent[vertex] != vertex)
			{
				parent[vertex] = parent[parent[vertex]];
				vertex = parent[vertex];
			}
			return vertex;
		}

		private static void Union(int[] parent, int left, int right)
		{
			int num = Find(parent, left);
			int num2 = Find(parent, right);
			if (num != num2)
			{
				parent[num2] = num;
			}
		}

		private static Transform FindBackAttachment(Player player)
		{
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			string[] obj = new string[5] { "attach_back", "attachback", "back_attach", "attach_backtool", "backtool" };
			Transform[] componentsInChildren = ((Component)player).GetComponentsInChildren<Transform>(true);
			string[] array = obj;
			foreach (string target in array)
			{
				Transform val = ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform transform) => string.Equals(Normalize(((Object)transform).name), target, StringComparison.OrdinalIgnoreCase)));
				if (Object.op_Implicit((Object)(object)val))
				{
					return val;
				}
			}
			Animator val2 = ((IEnumerable<Animator>)((Component)player).GetComponentsInChildren<Animator>(true)).FirstOrDefault((Func<Animator, bool>)((Animator candidate) => Object.op_Implicit((Object)(object)candidate) && candidate.isHuman));
			if (Object.op_Implicit((Object)(object)val2))
			{
				HumanBodyBones[] array2 = new HumanBodyBones[3];
				RuntimeHelpers.InitializeArray(array2, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
				HumanBodyBones[] array3 = (HumanBodyBones[])(object)array2;
				foreach (HumanBodyBones val3 in array3)
				{
					Transform boneTransform = val2.GetBoneTransform(val3);
					if (Object.op_Implicit((Object)(object)boneTransform))
					{
						return boneTransform;
					}
				}
			}
			return ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform transform) => Normalize(((Object)transform).name).Contains("spine2"))) ?? ((IEnumerable<Transform>)componentsInChildren).FirstOrDefault((Func<Transform, bool>)((Transform transform) => Normalize(((Object)transform).name).Contains("spine1")));
		}

		private static string Normalize(string value)
		{
			return (value ?? string.Empty).Replace(" ", string.Empty).Replace("-", string.Empty).ToLowerInvariant();
		}

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

		private static Mesh SourceMesh(Renderer renderer)
		{
			SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null);
			if ((Object)(object)val != (Object)null)
			{
				return val.sharedMesh;
			}
			MeshFilter component = ((Component)renderer).GetComponent<MeshFilter>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return null;
			}
			return component.sharedMesh;
		}

		private static bool ContainsGrowthToken(string identity)
		{
			string text = (identity ?? string.Empty).ToLowerInvariant();
			return GrowthTokens.Any(text.Contains);
		}

		private static string RelativePath(Transform transform, Transform root)
		{
			List<string> list = new List<string>();
			Transform val = transform;
			while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
			{
				list.Add(((Object)val).name);
				val = val.parent;
			}
			list.Reverse();
			return string.Join("/", list);
		}
	}
	internal static class CrookboundRootStaff
	{
		private const string ProjectilePrefab = "CrookboundRoot_ElderProjectile";

		private const string FieldRootPrefab = "CrookboundRoot_FieldRoot";

		private static readonly FieldRef<Attack, Humanoid> AttackCharacter = AccessTools.FieldRefAccess<Attack, Humanoid>("m_character");

		private static readonly FieldRef<Attack, ItemData> AttackWeapon = AccessTools.FieldRefAccess<Attack, ItemData>("m_weapon");

		private static readonly FieldRef<Humanoid, bool> IsSecondary = AccessTools.FieldRefAccess<Humanoid, bool>("m_currentAttackIsSecondary");

		private static GameObject _projectile;

		private static GameObject _fieldRoot;

		private static readonly Dictionary<long, float> NextRetaliation = new Dictionary<long, float>();

		internal static GameObject Projectile => _projectile;

		internal static void RegisterArmourRetaliation()
		{
			if (!Object.op_Implicit((Object)(object)_fieldRoot))
			{
				_fieldRoot = RegisterFieldRoot();
			}
		}

		internal static Attack BuildMergedSecondary(SharedData rootSpell)
		{
			if (rootSpell == null || rootSpell.m_attack == null)
			{
				throw new InvalidOperationException("Rootbound Crook's Elder secondary requires the live StaffGreenRoots attack.");
			}
			if (!Object.op_Implicit((Object)(object)_projectile))
			{
				_projectile = RegisterProjectile();
			}
			return BuildPrimary(Require(Object.op_Implicit((Object)(object)RootboundContent.FindPrefab("BMP_SurtlingStaff")) ? "BMP_SurtlingStaff" : "StaffFireball").GetComponent<ItemDrop>().m_itemData.m_shared.m_attack ?? throw new InvalidOperationException("Rootbound Crook's Elder secondary has no player projectile-cast architecture."), rootSpell.m_attack);
		}

		internal static void Register()
		{
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: 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_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = Require(Object.op_Implicit((Object)(object)RootboundContent.FindPrefab("BMP_SurtlingStaff")) ? "BMP_SurtlingStaff" : "StaffFireball");
			GameObject val = Require("StaffGreenRoots");
			SharedData shared = obj.GetComponent<ItemDrop>().m_itemData.m_shared;
			SharedData shared2 = val.GetComponent<ItemDrop>().m_itemData.m_shared;
			if (shared.m_attack == null || shared2.m_attack == null)
			{
				throw new InvalidOperationException("Crookbound Root requires live player-cast and StaffGreenRoots attack architectures.");
			}
			if (!Object.op_Implicit((Object)(object)_projectile))
			{
				_projectile = RegisterProjectile();
			}
			RegisterArmourRetaliation();
			ReclaimedStaffVisual.SourceVisualSnapshot sourceVisualSnapshot = ReclaimedStaffVisual.CaptureSource(obj);
			CustomItem val2 = new CustomItem(ReclaimedStaffVisual.CreateIsolatedItemPrefab(obj, "CrookboundRoot"), true);
			SharedData shared3 = val2.ItemDrop.m_itemData.m_shared;
			shared3.m_name = "$item_crookbound_root";
			shared3.m_description = "$item_crookbound_root_desc";
			shared3.m_maxQuality = shared2.m_maxQuality;
			shared3.m_skillType = shared2.m_skillType;
			shared3.m_attack = BuildPrimary(shared.m_attack, shared2.m_attack);
			shared3.m_secondaryAttack = BuildSecondary(shared2);
			shared3.m_damages = shared2.m_damages;
			shared3.m_damagesPerLevel = shared2.m_damagesPerLevel;
			shared3.m_attackForce = shared2.m_attackForce;
			shared3.m_backstabBonus = shared2.m_backstabBonus;
			shared3.m_attackStatusEffect = shared2.m_attackStatusEffect;
			shared3.m_attackStatusEffectChance = shared2.m_attackStatusEffectChance;
			shared3.m_hitEffect = shared2.m_hitEffect;
			shared3.m_hitTerrainEffect = shared2.m_hitTerrainEffect;
			ApplyBareCrookVisual(val2.ItemPrefab);
			sourceVisualSnapshot.Restore("Crookbound Root");
			ItemManager.Instance.AddItem(val2);
			AddRecipe(val2.ItemDrop);
			RootboundWitchPlugin.Log.LogInfo((object)"Crookbound Root registered: bare reclaimed branch, Elder 25-shot vine volley, 25 metre allied root field, and lifesteal on both attack modes.");
		}

		internal static bool IsOurSecondary(Attack attack)
		{
			if (attack == null)
			{
				return false;
			}
			Humanoid val = AttackCharacter.Invoke(attack);
			if ((Object)(object)val != (Object)null && IsSecondary.Invoke(val))
			{
				return RootboundState.HasPrefab(AttackWeapon.Invoke(attack), "CrookboundRoot");
			}
			return false;
		}

		internal static void CastField(Attack attack)
		{
			Humanoid obj = AttackCharacter.Invoke(attack);
			Player player = (Player)(object)((obj is Player) ? obj : null);
			ItemData val = AttackWeapon.Invoke(attack);
			if (RootboundSummonRecall.HasLocalAttackAuthority(player) && val != null && Object.op_Implicit((Object)(object)_fieldRoot))
			{
				SpawnField(player, val);
			}
		}

		internal static bool TryArmourRetaliation(Player player)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || ((Character)player).IsDead() || !RootboundState.IsFullSet(player) || !((Character)player).IsEncumbered() || !Object.op_Implicit((Object)(object)_fieldRoot))
			{
				return false;
			}
			long playerID = player.GetPlayerID();
			if (NextRetaliation.TryGetValue(playerID, out var value) && Time.time < value)
			{
				return false;
			}
			GameObject val = RootboundContent.FindPrefab("RootboundCrook");
			ItemDrop val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 == (Object)null)
			{
				RootboundWitchPlugin.Log.LogWarning((object)"Overencumbered retaliation could not resolve the Rootbound Crook damage ladder.");
				return false;
			}
			ItemData val3 = val2.m_itemData.Clone();
			val3.m_quality = Mathf.Clamp(RootboundState.MinimumQuality(player), 1, 4);
			NextRetaliation[playerID] = Time.time + Mathf.Max(1f, RootboundWitchPlugin.CrookboundFieldRetaliationCooldown.Value);
			SpawnField(player, val3);
			return true;
		}

		private static void SpawnField(Player player, ItemData weapon)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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)
			int num = Mathf.Clamp(RootboundWitchPlugin.CrookboundFieldRootCount.Value, 1, 64);
			float num2 = Mathf.Max(3f, RootboundWitchPlugin.CrookboundFieldRadius.Value);
			float num3 = Random.Range(0f, 360f);
			int num4 = 0;
			for (int i = 0; i < num; i++)
			{
				float num5 = ((float)i + 0.5f) / (float)num;
				float num6 = Mathf.Lerp(2.5f, num2, Mathf.Sqrt(num5));
				float num7 = num3 + (float)i * 137.50777f;
				if (TryFindGround(((Component)player).transform.position + Quaternion.Euler(0f, num7, 0f) * Vector3.forward * num6, out var ground))
				{
					GameObject obj = Object.Instantiate<GameObject>(_fieldRoot, ground, Quaternion.Euler(0f, num7 + 180f, 0f));
					obj.SetActive(true);
					CrookboundFieldRoot component = obj.GetComponent<CrookboundFieldRoot>();
					if ((Object)(object)component != (Object)null)
					{
						component.Assign(player, weapon);
					}
					num4++;
				}
			}
			RootboundWitchPlugin.Log.LogInfo((object)$"Rootbound overencumbered retaliation for {player.GetPlayerName()}: {num4}/{num} roots across {num2:0.#} m.");
		}

		private static Attack BuildPrimary(Attack playerCast, Attack rootAttack)
		{
			Attack obj = playerCast.Clone();
			obj.m_attackProjectile = _projectile;
			obj.m_projectiles = 1;
			obj.m_projectileBursts = 1;
			obj.m_burstInterval = 0f;
			obj.m_perBurstResourceUsage = false;
			obj.m_projectileAccuracy = 10f;
			obj.m_projectileAccuracyMin = 20f;
			obj.m_randomVelocity = false;
			obj.m_useCharacterFacing = false;
			obj.m_useCharacterFacingYAim = false;
			obj.m_damageMultiplier = 1f;
			obj.m_forceMultiplier = rootAttack.m_forceMultiplier;
			obj.m_attackEitr = rootAttack.m_attackEitr;
			obj.m_attackEitrAdd = rootAttack.m_attackEitrAdd;
			obj.m_attackHealth = 0f;
			obj.m_attackHealthPercentage = 0f;
			obj.m_attackHealthLowBlockUse = false;
			obj.m_attackHealthReturnHit = Mathf.Max(0f, RootboundWitchPlugin.CrookboundProjectileLifeReturn.Value);
			return obj;
		}

		private static Attack BuildSecondary(SharedData rootSpell)
		{
			Attack val = RootboundCrookSecondary.BuildAttack(rootSpell);
			val.m_attackEitr = ((rootSpell.m_attack != null) ? rootSpell.m_attack.m_attackEitr : val.m_attackEitr);
			val.m_attackEitrAdd = ((rootSpell.m_attack != null) ? rootSpell.m_attack.m_attackEitrAdd : 0f);
			val.m_attackHealth = 0f;
			val.m_attackHealthPercentage = 0f;
			val.m_attackHealthLowBlockUse = false;
			val.m_attackHealthReturnHit = 0f;
			val.m_spawnOnTrigger = null;
			val.m_spawnOnHit = null;
			val.m_spawnOnHitChance = 0f;
			val.m_damageMultiplier = 0f;
			val.m_forceMultiplier = 0f;
			return val;
		}

		private static GameObject RegisterProjectile()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: 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_007c: Expected O, but got Unknown
			GameObject val = Require("gdking_root_projectile");
			if ((Object)(object)val.GetComponent<Projectile>() == (Object)null)
			{
				throw new InvalidOperationException("gdking_root_projectile is not a live Projectile prefab.");
			}
			GameObject val2 = PrefabManager.Instance.CreateClonedPrefab("CrookboundRoot_ElderProjectile", val);
			val2.transform.localScale = Vector3.Scale(val2.transform.localScale, new Vector3(0.075f, 0.075f, 1f));
			val2.AddComponent<CrookboundVolleySeed>();
			PrefabManager.Instance.AddPrefab(new CustomPrefab(val2, true));
			return val2;
		}

		private static GameObject RegisterFieldRoot()
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Expected O, but got Unknown
			GameObject val = RootboundContent.FindPrefab("TentaRoot") ?? RootboundContent.FindPrefab("TentaRoot_wild");
			if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val.GetComponent<Character>() == (Object)null || (Object)(object)val.GetComponent<MonsterAI>() == (Object)null || (Object)(object)val.GetComponent<ZNetView>() == (Object)null)
			{
				throw new InvalidOperationException("Neither live Elder TentaRoot prefab can host the Crookbound field.");
			}
			GameObject val2 = PrefabManager.Instance.CreateClonedPrefab("CrookboundRoot_FieldRoot", val);
			Character component = val2.GetComponent<Character>();
			MonsterAI component2 = val2.GetComponent<MonsterAI>();
			component.m_name = "$enemy_crookbound_field_root";
			component.m_faction = (Faction)11;
			component.m_health = Mathf.Max(1f, component.m_health * 2f);
			component2.m_fleeIfLowHealth = 0f;
			component2.m_fleeIfHurtWhenTargetCantBeReached = false;
			CharacterDrop component3 = val2.GetComponent<CharacterDrop>();
			if ((Object)(object)component3 != (Object)null)
			{
				component3.m_drops.Clear();
			}
			SpawnArea component4 = val2.GetComponent<SpawnArea>();
			if ((Object)(object)component4 != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component4);
			}
			Tameable obj = val2.GetComponent<Tameable>() ?? val2.AddComponent<Tameable>();
			obj.m_startsTamed = true;
			obj.m_commandable = false;
			obj.m_unsummonOnOwnerLogoutSeconds = 10f;
			val2.AddComponent<CrookboundFieldRoot>();
			PrefabManager.Instance.AddPrefab(new CustomPrefab(val2, true));
			return val2;
		}

		private static void ApplyBareCrookVisual(GameObject staff)
		{
			//IL_0045: 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)
			ReclaimedStaffVisual.Apply(staff);
			ReclaimedStaffVisual.RemoveGeneratedOvergrowth(staff);
			FrostedStaffVisual.RemoveDeadCoreOnly(staff, "Crookbound Root");
			Light[] componentsInChildren = staff.GetComponentsInChildren<Light>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				((Behaviour)componentsInChildren[i]).enabled = false;
			}
			ParticleSystem[] componentsInChildren2 = staff.GetComponentsInChildren<ParticleSystem>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				EmissionModule emission = componentsInChildren2[i].emission;
				((EmissionModule)(ref emission)).enabled = false;
			}
		}

		private static bool TryFindGround(Vector3 candidate, out Vector3 ground)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			int mask = LayerMask.GetMask(new string[5] { "terrain", "Default", "static_solid", "piece", "piece_nonsolid" });
			RaycastHit val = default(RaycastHit);
			if (Physics.Raycast(candidate + Vector3.up * 35f, Vector3.down, ref val, 80f, mask, (QueryTriggerInteraction)1))
			{
				ground = ((RaycastHit)(ref val)).point + Vector3.up * 0.05f;
				return true;
			}
			ground = candidate;
			return false;
		}

		private static void AddRecipe(ItemDrop result)
		{
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Expected O, but got Unknown
			Recipe val = ScriptableObject.CreateInstance<Recipe>();
			((Object)val).name = "Recipe_CrookboundRoot";
			val.m_item = result;
			val.m_amount = 1;
			val.m_enabled = true;
			GameObject val2 = Require("piece_workbench");
			val.m_craftingStation = val2.GetComponent<CraftingStation>();
			val.m_repairStation = val.m_craftingStation;
			val.m_minStationLevel = 1;
			List<Requirement> list = new List<Requirement>();
			AddTier(list, 1, "MycelialCrook", 1);
			AddTier(list, 1, "CryptKey", 1);
			AddTier(list, 1, "Wishbone", 1);
			AddTier(list, 1, "Eitr", 30);
			AddTier(list, 2, "Eitr", 15);
			AddTier(list, 2, "YggdrasilWood", 10);
			AddTier(list, 2, "Mandible", 5);
			AddTier(list, 3, "AskHide", 6);
			AddTier(list, 3, "CelestialFeather", 4);
			AddTier(list, 3, "CharredBone", 8);
			AddTier(list, 4, FirstExisting("FrostCore", "Frostcore"), 3);
			AddTier(list, 4, FirstExisting("Frostwood", "FrostWood", "Timberwood"), 12);
			AddTier(list, 4, FirstExisting("MooseHide", "Moosehide"), 4);
			val.m_resources = list.ToArray();
			if (!ItemManager.Instance.AddRecipe(new CustomRecipe(val, false, false)))
			{
				throw new InvalidOperationException("Jotunn rejected " + ((Object)val).name);
			}
		}

		private static void AddTier(List<Requirement> requirements, int quality, string prefabName, int amount)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_0052: Expected O, but got Unknown
			ItemDrop component = Require(prefabName).GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				throw new InvalidOperationException("Crookbound Root recipe item has no ItemDrop: " + prefabName);
			}
			Requirement val = new Requirement
			{
				m_resItem = component,
				m_amount = ((quality == 1) ? 1 : 0),
				m_amountPerLevel = 0,
				m_recover = true,
				m_upgraderResource = false
			};
			requirements.Add(val);
			TieredRecipeCosts.Register(val, quality, amount);
		}

		private static string FirstExisting(params string[] candidates)
		{
			return candidates.FirstOrDefault((string candidate) => Object.op_Implicit((Object)(object)RootboundContent.FindPrefab(candidate))) ?? throw new InvalidOperationException("Crookbound Root upgrade material is missing: " + string.Join("|", candidates));
		}

		private static GameObject Require(string name)
		{
			GameObject obj = RootboundContent.FindPrefab(name);
			if (!Object.op_Implicit((Object)(object)obj))
			{
				throw new InvalidOperationException("Crookbound Root requires live prefab: " + name);
			}
			return obj;
		}
	}
	internal sealed class CrookboundVolleySeed : MonoBehaviour
	{
		private static readonly FieldRef<Projectile, Vector3> Velocity = AccessTools.FieldRefAccess<Projectile, Vector3>("m_vel");

		private bool _continuation;

		internal void MarkContinuation()
		{
			_continuation = true;
		}

		private void Start()
		{
			//IL_005d: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			if (_continuation || !Object.op_Implicit((Object)(object)RootboundWitchPlugin.Instance))
			{
				return;
			}
			Projectile component = ((Component)this).GetComponent<Projectile>();
			Character val = (Object.op_Implicit((Object)(object)component) ? FrostedRootProjectileState.Owner(component) : null);
			Player val2 = (Player)(object)((val is Player) ? val : null);
			if (!Object.op_Implicit((Object)(object)component) || ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)Player.m_localPlayer))
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)val))
			{
				Vector3 val3 = val.GetLookDir();
				if (((Vector3)(ref val3)).sqrMagnitude < 0.01f)
				{
					val3 = ((Component)val).transform.forward;
				}
				((Component)component).transform.position = val.GetEyePoint() + ((Vector3)(ref val3)).normalized * 0.45f;
			}
			((MonoBehaviour)RootboundWitchPlugin.Instance).StartCoroutine(ContinueVolley(component));
		}

		private static IEnumerator ContinueVolley(Projectile seed)
		{
			Character owner = FrostedRootProjectileState.Owner(seed);
			HitData hit = FrostedRootProjectileState.HitData(seed);
			ItemData weapon = FrostedRootProjectileState.Weapon(seed);
			ItemData ammo = FrostedRootProjectileState.Ammo(seed);
			Vector3 localMuzzle = (Object.op_Implicit((Object)(object)owner) ? ((Component)owner).transform.InverseTransformPoint(((Component)seed).transform.position) : Vector3.zero);
			Vector3 val = Velocity.Invoke(seed);
			float speed = Mathf.Max(8f, ((Vector3)(ref val)).magnitude);
			Vector3 val2;
			Vector3 lookDir;
			if (!(((Vector3)(ref val)).sqrMagnitude > 0.01f))
			{
				if (!Object.op_Implicit((Object)(object)owner))
				{
					val2 = Vector3.forward;
				}
				else
				{
					lookDir = owner.GetLookDir();
					val2 = ((Vector3)(ref lookDir)).normalized;
				}
			}
			else
			{
				val2 = ((Vector3)(ref val)).normalized;
			}
			Vector3 fallbackForward = val2;
			float hitNoise = seed.m_hitNoise;
			int index = 1;
			while (index < 25)
			{
				yield return (object)new WaitForSeconds(0.1f);
				GameObject projectile = CrookboundRootStaff.Projectile;
				if (!Object.op_Implicit((Object)(object)owner) || !Object.op_Implicit((Object)(object)projectile))
				{
					break;
				}
				Vector3 val3 = ((Component)owner).transform.TransformPoint(localMuzzle);
				lookDir = owner.GetLookDir();
				Vector3 val4 = ((Vector3)(ref lookDir)).normalized;
				if (((Vector3)(ref val4)).sqrMagnitude < 0.01f)
				{
					val4 = fallbackForward;
				}
				Vector2 val5 = Random.insideUnitCircle * 5f;
				Vector3 val6 = Quaternion.Euler(0f - val5.y, val5.x, 0f) * val4;
				GameObject obj = Object.Instantiate<GameObject>(projectile, val3, Quaternion.LookRotation(val6));
				CrookboundVolleySeed component = obj.GetComponent<CrookboundVolleySeed>();
				if ((Object)(object)component != (Object)null)
				{
					component.MarkContinuation();
				}
				obj.GetComponent<Projectile>().Setup(owner, val6 * speed, hitNoise, (HitData)((hit != null) ? ((object)hit.Clone()) : ((object)new HitData())), weapon, ammo);
				int num = index + 1;
				index = num;
			}
		}
	}
	internal sealed class CrookboundFieldRoot : MonoBehaviour
	{
		private const string OwnerKey = "ADARC_CrookboundRootOwner";

		private const string ExpiresKey = "ADARC_CrookboundRootExpires";

		private const string QualityKey = "ADARC_CrookboundRootQuality";

		private const string DamageKey = "ADARC_CrookboundRootDamage_";

		private ZNetView _view;

		private MonsterAI _ai;

		private Character _character;

		private long _ownerId;

		private float _expiresAt;

		private DamageTypes _damage;

		private void Awake()
		{
			_view = ((Component)this).GetComponent<ZNetView>();
			_ai = ((Component)this).GetComponent<MonsterAI>();
			_character = ((Component)this).GetComponent<Character>();
			if ((Object)(object)_ai != (Object)null)
			{
				_ai.MakeTame();
				_ai.SetDespawnInDay(false);
			}
			ReadState();
		}

		private void Update()
		{
			ReadState();
			if (!(_expiresAt <= 0f) && !(Time.time < _expiresAt) && !((Object)(object)_character == (Object)null) && !_character.IsDead() && ((Object)(object)_view == (Object)null || _view.GetZDO() == null || _view.IsOwner()))
			{
				RootboundSummonRecall.Kill(_character, _view);
			}
		}

		internal void Assign(Player owner, ItemData weapon)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			_ownerId = owner.GetPlayerID();
			_expiresAt = Time.time + Mathf.Max(5f, RootboundWitchPlugin.CrookboundFieldDuration.Value);
			_damage = weapon.GetDamage();
			if ((Object)(object)_view != (Object)null && _view.GetZDO() != null)
			{
				ZDO zDO = _view.GetZDO();
				zDO.Set("ADARC_CrookboundRootOwner", _ownerId);
				zDO.Set("ADARC_CrookboundRootExpires", _expiresAt);
				zDO.Set("ADARC_CrookboundRootQuality", weapon.m_quality);
				WriteDamage(zDO, _damage);
			}
			if ((Object)(object)_ai != (Object)null)
			{
				_ai.MakeTame();
			}
		}

		internal bool TryPrepareHit(Character target, ref HitData hit)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			ReadState();
			if ((Object)(object)_view != (Object)null && _view.GetZDO() != null && !_view.IsOwner())
			{
				return false;
			}
			Player val = ((IEnumerable<Player>)Player.GetAllPlayers()).FirstOrDefault((Func<Player, bool>)((Player player) => (Object)(object)player != (Object)null && player.GetPlayerID() == _ownerId));
			if ((Object)(object)val == (Object)null || (Object)(object)target == (Object)null || target.IsDead() || !BaseAI.IsEnemy((Character)(object)val, target))
			{
				return false;
			}
			hit.m_damage = _damage;
			hit.m_skill = (SkillType)9;
			if ((Object)(object)_view != (Object)null && _view.GetZDO() != null)
			{
				hit.m_itemLevel = (short)Mathf.Max(1, _view.GetZDO().GetInt("ADARC_CrookboundRootQuality", 1));
			}
			float num = Mathf.Max(0f, hit.GetTotalDamage()) * Mathf.Clamp01(RootboundWitchPlugin.CrookboundFieldLifeStealFraction.Value);
			if (num > 0.001f)
			{
				((Character)val).Heal(num, true);
			}
			return true;
		}

		private void ReadState()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_view == (Object)null) && _view.GetZDO() != null)
			{
				ZDO zDO = _view.GetZDO();
				_ownerId = zDO.GetLong("ADARC_CrookboundRootOwner", _ownerId);
				_expiresAt = zDO.GetFloat("ADARC_CrookboundRootExpires", _expiresAt);
				_damage = ReadDamage(zDO, _damage);
			}
		}

		private static void WriteDamage(ZDO zdo, DamageTypes damage)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			zdo.Set("ADARC_CrookboundRootDamage_raw", damage.m_damage);
			zdo.Set("ADARC_CrookboundRootDamage_blunt", damage.m_blunt);
			zdo.Set("ADARC_CrookboundRootDamage_slash", damage.m_slash);
			zdo.Set("ADARC_CrookboundRootDamage_pierce", damage.m_pierce);
			zdo.Set("ADARC_CrookboundRootDamage_fire", damage.m_fire);
			zdo.Set("ADARC_CrookboundRootDamage_frost", damage.m_frost);
			zdo.Set("ADARC_CrookboundRootDamage_lightning", damage.m_lightning);
			zdo.Set("ADARC_CrookboundRootDamage_poison", damage.m_poison);
			zdo.Set("ADARC_CrookboundRootDamage_spirit", damage.m_spirit);
			zdo.Set("ADARC_CrookboundRootDamage_chop", damage.m_chop);
			zdo.Set("ADARC_CrookboundRootDamage_pickaxe", damage.m_pickaxe);
		}

		private static DamageTypes ReadDamage(ZDO zdo, DamageTypes fallback)
		{
			//IL_0002: 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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			return new DamageTypes
			{
				m_damage = zdo.GetFloat("ADARC_CrookboundRootDamage_raw", fallback.m_damage),
				m_blunt = zdo.GetFloat("ADARC_CrookboundRootDamage_blunt", fallback.m_blunt),
				m_slash = zdo.GetFloat("ADARC_CrookboundRootDamage_slash", fallback.m_slash),
				m_pierce = zdo.GetFloat("ADARC_CrookboundRootDamage_pierce", fallback.m_pierce),
				m_fire = zdo.GetFloat("ADARC_CrookboundRootDamage_fire", fallback.m_fire),
				m_frost = zdo.GetFloat("ADARC_CrookboundRootDamage_frost", fallback.m_frost),
				m_lightning = zdo.GetFloat("ADARC_CrookboundRootDamage_lightning", fallback.m_lightning),
				m_poison = zdo.GetFloat("ADARC_CrookboundRootDamage_poison", fallback.m_poison),
				m_spirit = zdo.GetFloat("ADARC_CrookboundRootDamage_spirit", fallback.m_spirit),
				m_chop = zdo.GetFloat("ADARC_CrookboundRootDamage_chop", fallback.m_chop),
				m_pickaxe = zdo.GetFloat("ADARC_CrookboundRootDamage_pickaxe", fallback.m_pickaxe)
			};
		}
	}
	[HarmonyPatch(typeof(Character), "Damage")]
	internal static class CrookboundFieldLifestealPatch
	{
		private static bool Prefix(Character __instance, ref HitData hit)
		{
			Character val = ((hit != null) ? hit.GetAttacker() : null);
			CrookboundFieldRoot crookboundFieldRoot = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent<CrookboundFieldRoot>() : null);
			if ((Object)(object)crookboundFieldRoot == (Object)null)
			{
				return true;
			}
			return crookboundFieldRoot.TryPrepareHit(__instance, ref hit);
		}
	}
	[HarmonyPatch(typeof(Character), "RPC_Damage")]
	internal static class RootboundOverencumberedRetaliationPatch
	{
		private static void Postfix(Character __instance, HitData __1)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			Character val2 = ((__1 != null) ? __1.GetAttacker() : null);
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)val) && !(__1.GetTotalDamage() <= 0.001f) && BaseAI.IsEnemy((Character)(object)val, val2))
			{
				CrookboundRootStaff.TryArmourRetaliation(val);
			}
		}
	}
	internal static class DraconicCrook
	{
		private const string FissureAoeName = "Fader_Fissure_AOE";

		private const string FissureAoePath = "Assets/Characters/Fader/attacks/Fader_Fissure_AOE.prefab";

		private const string MeteorName = "projectile_meteor_fader";

		private const string MeteorPath = "Assets/Characters/Fader/attacks/projectile_meteor_fader.prefab";

		private const string MeteorAftermathPrefab = "DraconicCrook_MeteorAftermath";

		private const float DamagePerGrowth = 10f;

		private static readonly FieldRef<Attack, Humanoid> AttackCharacter = AccessTools.FieldRefAccess<Attack, Humanoid>("m_character");

		private static readonly FieldRef<Attack, ItemData> AttackWeapon = AccessTools.FieldRefAccess<Attack, ItemData>("m_weapon");

		private static readonly FieldRef<Humanoid, bool> IsSecondary = AccessTools.FieldRefAccess<Humanoid, bool>("m_currentAttackIsSecondary");

		private static SoftReference<GameObject> _fissureReference;

		private static SoftReference<GameObject> _meteorReference;

		private static GameObject _fissureAoe;

		private static GameObject _meteor;

		private static GameObject _meteorAftermath;

		internal static void Register()
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Expected O, but got Unknown
			//IL_0117: 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)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = Require("StaffIceShards");
			ItemDrop component = obj.GetComponent<ItemDrop>();
			Attack val = (((Object)(object)component != (Object)null) ? component.m_itemData.m_shared.m_attack : null);
			if (val == null)
			{
				throw new InvalidOperationException("Draconic Crook requires the live StaffIceShards item and its player-cast attack architecture.");
			}
			_fissureAoe = ResolveCombatPrefab("Fader_Fissure_AOE", "Assets/Characters/Fader/attacks/Fader_Fissure_AOE.prefab", ref _fissureReference);
			_meteor = ResolveCombatPrefab("projectile_meteor_fader", "Assets/Characters/Fader/attacks/projectile_meteor_fader.prefab", ref _meteorReference);
			if (!Object.op_Implicit((Object)(object)_fissureAoe) || (Object)(object)_fissureAoe.GetComponent<Aoe>() == (Object)null)
			{
				throw new InvalidOperationException("Fader_Fissure_AOE did not resolve to the live grausten-spike AOE.");
			}
			if (!Object.op_Implicit((Object)(object)_meteor) || (Object)(object)_meteor.GetComponent<Projectile>() == (Object)null)
			{
				throw new InvalidOperationException("projectile_meteor_fader did not resolve to the live Fader meteor projectile.");
			}
			_meteorAftermath = RegisterMeteorAftermath(_meteor);
			ReclaimedStaffVisual.SourceVisualSnapshot sourceVisualSnapshot = ReclaimedStaffVisual.CaptureSource(obj);
			CustomItem val2 = new CustomItem(ReclaimedStaffVisual.CreateIsolatedItemPrefab(obj, "DraconicCrook"), true);
			SharedData shared = val2.ItemDrop.m_itemData.m_shared;
			shared.m_name = "$item_draconic_crook";
			shared.m_description = "$item_draconic_crook_desc";
			shared.m_maxQuality = 4;
			shared.m_skillType = (SkillType)9;
			shared.m_attack = BuildAttack(val, RootboundWitchPlugin.DraconicFissureEitr.Value);
			shared.m_secondaryAttack = BuildAttack(val, RootboundWitchPlugin.DraconicMeteorEitr.Value);
			shared.m_damages = default(DamageTypes);
			shared.m_damagesPerLevel = default(DamageTypes);
			shared.m_attackForce = 0f;
			shared.m_attackStatusEffect = null;
			shared.m_attackStatusEffectChance = 0f;
			DraconicCrookVisual.Apply(val2.ItemPrefab);
			RootboundStaffIcons.Apply(shared, RootboundStaffIcon.DraconicCrook);
			sourceVisualSnapshot.Restore("Draconic Crook");
			ItemManager.Instance.AddItem(val2);
			AddRecipe(val2.ItemDrop);
			RootboundWitchPlugin.Log.LogInfo((object)"Draconic Crook registered from an isolated StaffIceShards body. Primary deploys Fader's exact 12-15 grausten fissures; secondary deploys the exact ten-projectile Fader meteor shower. Four growths add ten damage to every authored damage channel per upgrade. Vanilla StaffIceShards visuals were source-audited and retained.");
		}

		internal static bool IsOurAttack(Attack attack)
		{
			if (attack != null)
			{
				return RootboundState.HasPrefab(AttackWeapon.Invoke(attack), "DraconicCrook");
			}
			return false;
		}

		internal static bool HandleAttack(Attack attack)
		{
			Humanoid obj = AttackCharacter.Invoke(attack);
			Player val = (Player)(object)((obj is Player) ? obj : null);
			ItemData val2 = AttackWeapon.Invoke(attack);
			if (!RootboundSummonRecall.HasLocalAttackAuthority(val) || val2 == null)
			{
				return false;
			}
			if (!RootboundAttackTransaction.TryBegin(attack))
			{
				return false;
			}
			IEnumerator enumerator = (IsSecondary.Invoke((Humanoid)(object)val) ? CastMeteorShower(val, val2) : CastFissureField(val, val2));
			if (Object.op_Implicit((Object)(object)RootboundWitchPlugin.Instance))
			{
				((MonoBehaviour)RootboundWitchPlugin.Instance).StartCoroutine(enumerator);
			}
			return false;
		}

		private static Attack BuildAttack(Attack source, float eitr)
		{
			Attack obj = source.Clone();
			obj.m_projectiles = 1;
			obj.m_projectileBursts = 1;
			obj.m_burstInterval = 0f;
			obj.m_perBurstResourceUsage = false;
			obj.m_projectileAccuracy = 0f;
			obj.m_projectileAccuracyMin = 0f;
			obj.m_randomVelocity = false;
			obj.m_useCharacterFacing = false;
			obj.m_useCharacterFacingYAim = false;
			obj.m_attackEitr = Mathf.Max(0f, eitr);
			obj.m_attackEitrAdd = 0f;
			obj.m_attackStamina = 0f;
			obj.m_attackHealth = 0f;
			obj.m_attackHealthPercentage = 0f;
			obj.m_attackHealthLowBlockUse = false;
			obj.m_attackHealthReturnHit = 0f;
			obj.m_damageMultiplier = 0f;
			obj.m_forceMultiplier = 0f;
			return obj;
		}

		private static IEnumerator CastFissureField(Player player, ItemData weapon)
		{
			int count = Random.Range(12, 16);
			int index = 0;
			while (index < count && Object.op_Implicit((Object)(object)player) && !((Character)player).IsDead() && Object.op_Implicit((Object)(object)_fissureAoe))
			{
				Vector3 val = FindTargetPoint(player);
				GameObject obj = Object.Instantiate<GameObject>(_fissureAoe, val + Vector3.up * 0.2f, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f));
				Aoe component = obj.GetComponent<Aoe>();
				component.m_damagePerLevel = GrowthPacket(component.m_damage);
				component.Setup((Character)(object)player, Vector3.zero, -1f, (HitData)null, weapon, (ItemData)null);
				obj.SetActive(true);
				yield return (object)new WaitForSeconds(0.45f);
				int num = index + 1;
				index = num;
			}
		}

		private static IEnumerator CastMeteorShower(Player player, ItemData weapon)
		{
			int index = 0;
			while (index < 10 && Object.op_Implicit((Object)(object)player) && !((Character)player).IsDead() && Object.op_Implicit((Object)(object)_meteor))
			{
				Vector3 val = FindTargetPoint(player);
				Vector2 val2 = Random.insideUnitCircle * 15f;
				Vector3 val3 = val + new Vector3(val2.x, 90f, val2.y);
				Vector3 val4 = val - val3;
				Vector3 val5 = ((Vector3)(ref val4)).normalized * 30f;
				GameObject obj = Object.Instantiate<GameObject>(_meteor, val3, Quaternion.LookRotation(val5));
				Projectile component = obj.GetComponent<Projectile>();
				if (Object.op_Implicit((Object)(object)_meteorAftermath))
				{
					component.m_spawnOnHit = _meteorAftermath;
				}
				component.Setup((Character)(object)player, val5, -1f, (HitData)null, weapon, (ItemData)null);
				component.m_damage = DamageAtQuality(component.m_damage, weapon.m_quality);
				obj.SetActive(true);
				yield return (object)new WaitForSeconds(0.5f);
				int num = index + 1;
				index = num;
			}
		}

		private static GameObject RegisterMeteorAftermath(GameObject meteor)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			Projectile component = meteor.GetComponent<Projectile>();
			GameObject val = (((Object)(object)component != (Object)null) ? component.m_spawnOnHit : null);
			Aoe[] array = (Aoe[])(Object.op_Implicit((Object)(object)val) ? ((Array)val.GetComponentsInChildren<Aoe>(true)) : ((Array)new Aoe[0]));
			if (!Object.op_Implicit((Object)(object)val) || array.Length == 0)
			{
				throw new InvalidOperationException("Fader meteor has no live AOE aftermath to make quality-aware.");
			}
			GameObject val2 = PrefabManager.Instance.CreateClonedPrefab("DraconicCrook_MeteorAftermath", val);
			Aoe[] componentsInChildren = val2.GetComponentsInChildren<Aoe>(true);
			foreach (Aoe obj in componentsInChildren)
			{
				obj.m_damagePerLevel = GrowthPacket(obj.m_damage);
			}
			PrefabManager.Instance.AddPrefab(new CustomPrefab(val2, true));
			return val2;
		}

		private static DamageTypes GrowthPacket(DamageTypes authored)
		{
			//IL_0002: 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)
			//IL_002a: 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_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: 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_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			return new DamageTypes
			{
				m_blunt = ((authored.m_blunt > 0f) ? 10f : 0f),
				m_slash = ((authored.m_slash > 0f) ? 10f : 0f),
				m_pierce = ((authored.m_pierce > 0f) ? 10f : 0f),
				m_chop = ((authored.m_chop > 0f) ? 10f : 0f),
				m_pickaxe = ((authored.m_pickaxe > 0f) ? 10f : 0f),
				m_fire = ((authored.m_fire > 0f) ? 10f : 0f),
				m_frost = ((authored.m_frost > 0f) ? 10f : 0f),
				m_lightning = ((authored.m_lightning > 0f) ? 10f : 0f),
				m_poison = ((authored.m_poison > 0f) ? 10f : 0f),
				m_spirit = ((authored.m_spirit > 0f) ? 10f : 0f)
			};
		}

		private static DamageTypes DamageAtQuality(DamageTypes authored, int quality)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Clamp(quality, 1, 4) - 1;
			if (num <= 0)
			{
				return authored;
			}
			DamageTypes val = GrowthPacket(authored);
			((DamageTypes)(ref authored)).Add(val, num);
			return authored;
		}

		private static Vector3 FindTargetPoint(Player player)
		{
			//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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			Vector3 eyePoint = ((Character)player).GetEyePoint();
			Vector3 lookDir = ((Character)player).GetLookDir();
			Vector3 normalized = ((Vector3)(ref lookDir)).normalized;
			RaycastHit val2 = default(RaycastHit);
			Vector3 val = (Physics.Raycast(eyePoint, normalized, ref val2, 4096f, -1, (QueryTriggerInteraction)1) ? ((RaycastHit)(ref val2)).point : (eyePoint + normalized * 80f));
			int mask = LayerMask.GetMask(new string[5] { "terrain", "Default", "static_solid", "piece", "piece_nonsolid" });
			RaycastHit val3 = default(RaycastHit);
			if (Physics.Raycast(val + Vector3.up * 60f, Vector3.down, ref val3, 180f, mask, (QueryTriggerInteraction)1))
			{
				return ((RaycastHit)(ref val3)).point + Vector3.up * 0.05f;
			}
			return val;
		}

		private static GameObject ResolveCombatPrefab(string shortName, string fullPath, ref SoftReference<GameObject> heldReference)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = RootboundContent.FindPrefab(shortName);
			if (Object.op_Implicit((Object)(object)val))
			{
				return val;
			}
			string[] array = new string[2] { shortName, fullPath };
			foreach (string text in array)
			{
				try
				{
					heldReference = AssetManager.Instance.GetSoftReference<GameObject>(text);
					if (heldReference.IsValid)
					{
						heldReference.Load();
						heldReference.WaitForLoadToComplete();
						val = heldReference.Asset;
						if (Object.op_Implicit((Object)(object)val))
						{
							heldReference.HoldReference();
							RootboundWitchPlugin.Log.LogInfo((object)("Draconic Crook resolved live Fader asset '" + text + "'."));
							return val;
						}
					}
				}
				catch (Exception ex)
				{
					RootboundWitchPlugin.Log.LogWarning((object)("Draconic Crook Fader asset candidate '" + text + "' failed: " + ex.Message));
				}
			}
			return null;
		}

		private static void AddRecipe(ItemDrop result)
		{
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Expected O, but got Unknown
			Recipe val = ScriptableObject.CreateInstance<Recipe>();
			((Object)val).name = "Recipe_DraconicCrook";
			val.m_item = result;
			val.m_amount = 1;
			val.m_enabled = true;
			val.m_craftingStation = Require("piece_magetable").GetComponent<CraftingStation>();
			val.m_repairStation = val.m_craftingStation;
			val.m_minStationLevel = 4;
			List<Requirement> list = new List<Requirement>();
			AddTier(list, 1, "StaffIceShards", 1);
			AddTier(list, 1, "TrophyFader", 2);
			AddTier(list, 1, "FaderEmber", 15);
			AddTier(list, 1, "GemstoneGreen", 3);
			AddTier(list, 1, "Eitr", 65);
			AddTier(list, 2, "TrophyFader", 1);
			AddTier(list, 2, "FaderEmber", 10);
			AddTier(list, 2, "Eitr", 20);
			AddTier(list, 3, "TrophyFader", 1);
			AddTier(list, 3, "FaderEmber", 15);
			AddTier(list, 3, "GemstoneGreen", 1);
			AddTier(list, 3, "Eitr", 30);
			AddTier(list, 4, "TrophyFader", 1);
			AddTier(list, 4, "FaderEmber", 20);
			AddTier(list, 4, "GemstoneGreen", 2);
			AddTier(list, 4, "Eitr", 40);
			val.m_resources = list.ToArray();
			if (!ItemManager.Instance.AddRecipe(new CustomRecipe(val, false, false)))
			{
				throw new InvalidOperationException("Jotunn rejected " + ((Object)val).name);
			}
		}

		private static void AddTier(List<Requirement> requirements, int quality, string prefabName, int amount)
		{
			Requirement val = Requirement(prefabName, (quality == 1) ? 1 : 0);
			val.m_amountPerLevel = 0;
			val.m_upgraderResource = false;
			requirements.Add(val);
			TieredRecipeCosts.Register(val, quality, amount);
		}

		private static Requirement Requirement(string prefabName, int amount)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			ItemDrop component = Require(prefabName).GetComponent<ItemDrop>();
			if ((Object)(object)component == (Object)null)
			{
				throw new InvalidOperationException("Draconic Crook recipe item is missing: " + prefabName);
			}
			return new Requirement
			{
				m_resItem = component,
				m_amount = amount,
				m_amountPerLevel = 0,
				m_upgraderResource = false,
				m_recover = true
			};
		}

		private static GameObject Require(string prefabName)
		{
			GameObject obj = RootboundContent.FindPrefab(prefabName);
			if (!Object.op_Implicit((Object)(object)obj))
			{
				throw new InvalidOperationException("Draconic Crook requires live prefab: " + prefabName);
			}
			return obj;
		}
	}
	internal static class DraconicCrookVisual
	{
		private static readonly Color RotDark = new Color(0.006f, 0.022f, 0.01f, 0.07f);

		private static readonly Color RotLight = new Color(0.035f, 0.12f, 0.04f, 0.17f);

		private static readonly Color SolidRot = new Color(0.035f, 0.18f, 0.055f, 1f);

		private static readonly string[] ColourProperties = new string[3] { "_Color", "_BaseColor", "_TintColor" };

		internal static void Apply(GameObject staff)
		{
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Expected O, but got Unknown
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)staff))
			{
				return;
			}
			ReclaimedStaffVisual.DisableUpgradeGlow(staff);
			Renderer[] componentsInChildren = staff.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				bool flag = val is ParticleSystemRenderer || val is TrailRenderer || val is LineRenderer;
				Material[] sharedMaterials = val.sharedMaterials;
				Material[] array = (Material[])(object)new Material[sharedMaterials.Length];
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					if (!Object.op_Implicit((Object)(object)sharedMaterials[j]))
					{
						continue;
					}
					Material val2 = new Material(sharedMaterials[j])
					{
						name = ((Object)sharedMaterials[j]).name + "_DraconicCrookIsolated"
					};
					string[] colourProperties = ColourProperties;
					foreach (string text in colourProperties)
					{
						if (val2.HasProperty(text))
						{
							val2.SetColor(text, flag ? RotLight : SolidRot);
						}
					}
					if (val2.HasProperty("_EmissionColor"))
					{
						val2.SetColor("_EmissionColor", Color.black);
					}
					val2.DisableKeyword("_EMISSION");
					if (flag)
					{
						MakeTransparent(val2);
					}
					array[j] = val2;
				}
				val.sharedMaterials = array;
				TrailRenderer val3 = (TrailRenderer)(object)((val is TrailRenderer) ? val : null);
				if (Object.op_Implicit((Object)(object)val3))
				{
					val3.startColor = RotLight;
					val3.endColor = RotDark;
				}
				LineRenderer val4 = (LineRenderer)(object)((val is LineRenderer) ? val : null);
				if (Object.op_Implicit((Object)(object)val4))
				{
					val4.startColor = RotLight;
					val4.endColor = RotDark;
				}
			}
			ParticleSystem[] componentsInChildren2 = staff.GetComponentsInChildren<ParticleSystem>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				MainModule main = componentsInChildren2[i].main;
				((MainModule)(ref main)).startColor = new MinMaxGradient(RotDark, RotLight);
			}
			Light[] componentsInChildren3 = staff.GetComponentsInChildren<Light>(true);
			foreach (Light obj in componentsInChildren3)
			{
				obj.color = SolidRot;
				obj.intensity = Mathf.Min(obj.intensity, 0.12f);
				obj.range = Mathf.Min(obj.range, 3f);
			}
		}

		private static void MakeTransparent(Material material)
		{
			if (material.HasProperty("_Surface"))
			{
				material.SetFloat("_Surface", 1f);
			}
			if (material.HasProperty("_Mode"))
			{
				material.SetFloat("_Mode", 3f);
			}
			if (material.HasProperty("_SrcBlend"))
			{
				material.SetInt("_SrcBlend", 5);
			}
			if (material.HasProperty("_DstBlend"))
			{
				material.SetInt("_DstBlend", 10);
			}
			if (material.HasProperty("_ZWrite"))
			{
				material.SetInt("_ZWrite", 0);
			}
			material.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
			material.EnableKeyword("_ALPHABLEND_ON");
			material.DisableKeyword("_ALPHATEST_ON");
			material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
			material.renderQueue = 3000;
		}
	}
	internal static class DraugrRotVisuals
	{
		private const string ProjectilePrefabName = "RootboundCrook_DraugrRotProjectile";

		private static readonly Color RotDark = new Color(0.006f, 0.022f, 0.01f, 0.1f);

		private static readonly Color RotLight = new Color(0.045f, 0.115f, 0.038f, 0.26f);

		private static readonly string[] ColourProperties = new string[3] { "_Color", "_BaseColor", "_TintColor" };

		private static GameObject _projectile;

		internal static void ApplyToAttack(Attack attack)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			if (attack != null && Object.op_Implicit((Object)(object)attack.m_attackProjectile))
			{
				if (!Object.op_Implicit((Object)(object)_projectile))
				{
					_projectile = PrefabManager.Instance.CreateClonedPrefab("RootboundCrook_DraugrRotProjectile", attack.m_attackProjectile);
					_projectile.AddComponent<RootboundTriangleProjectile>();
					Recolour(_projectile);
					PrefabManager.Instance.AddPrefab(new CustomPrefab(_projectile, true));
					RootboundWitchPlugin.Log.LogInfo((object)("Rootbound Crook projectile recoloured to the draugr-rot palette from " + ((Object)attack.m_attackProjectile).name + "."));
				}
				attack.m_attackProjectile = _projectile;
			}
		}

		internal static void Recolour(GameObject visual, bool keepSolidGeometryOpaque = false)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)visual))
			{
				return;
			}
			ParticleSystem[] componentsInChildren = visual.GetComponentsInChildren<ParticleSystem>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				MainModule main = componentsInChildren[i].main;
				Color rotDark = RotDark;
				Color rotLight = RotLight;
				((MainModule)(ref main)).startColor = new MinMaxGradient(rotDark, rotLight);
			}
			Light[] componentsInChildren2 = visual.GetComponentsInChildren<Light>(true);
			foreach (Light obj in componentsInChildren2)
			{
				((Behaviour)obj).enabled = false;
				obj.intensity = 0f;
			}
			Renderer[] componentsInChildren3 = visual.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren3)
			{
				Material[] array = ((IEnumerable<Material>)val.sharedMaterials).Select((Func<Material, Material>)((Material material) => Object.op_Implicit((Object)(object)material) ? new Material(material) : ((Material)null))).ToArray();
				Material[] array2 = array;
				for (int num = 0; num < array2.Length; num++)
				{
					Tint(array2[num], val is ParticleSystemRenderer || val is TrailRenderer, keepSolidGeometryOpaque);
				}
				val.sharedMaterials = array;
			}
		}

		private static void Tint(Material material, bool airborne, bool keepSolidGeometryOpaque)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)material))
			{
				return;
			}
			((Object)material).name = ((Object)material).name + "_DraugrRot";
			string[] colourProperties = ColourProperties;
			foreach (string text in colourProperties)
			{
				if (material.HasProperty(text))
				{
					Color color = material.GetColor(text);
					Color val = Color.Lerp(RotDark, RotLight, Mathf.Clamp01(((Color)(ref color)).grayscale));
					val.a = (airborne ? 0.2f : (keepSolidGeometryOpaque ? 1f : Mathf.Min(0.42f, Mathf.Max(0.22f, color.a * 0.38f))));
					material.SetColor(text, val);
				}
			}
			if (material.HasProperty("_EmissionColor"))
			{
				material.SetColor("_EmissionColor", Color.black);
			}
			material.DisableKeyword("_EMISSION");
			if (airborne)
			{
				if (material.HasProperty("_Surface"))
				{
					material.SetFloat("_Surface", 1f);
				}
				if (material.HasProperty("_Mode"))
				{
					material.SetFloat("_Mode", 3f);
				}
				if (material.HasProperty("_SrcBlend"))
				{
					material.SetInt("_SrcBlend", 5);
				}
				if (material.HasProperty("_DstBlend"))
				{
					material.SetInt("_DstBlend", 10);
				}
				if (material.HasProperty("_ZWrite"))
				{
					material.SetInt("_ZWrite", 0);
				}
				material.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
				material.EnableKeyword("_ALPHABLEND_ON");
				material.DisableKeyword("_ALPHATEST_ON");
				material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
				material.renderQueue = 3000;
			}
			else if (keepSolidGeometryOpaque)
			{
				if (material.HasProperty("_Surface"))
				{
					material.SetFloat("_Surface", 0f);
				}
				if (material.HasProperty("_Mode"))
				{
					material.SetFloat("_Mode", 0f);
				}
				if (material.HasProperty("_SrcBlend"))
				{
					material.SetInt("_SrcBlend", 1);
				}
				if (material.HasProperty("_DstBlend"))
				{
					material.SetInt("_DstBlend", 0);
				}
				if (material.HasProperty("_ZWrite"))
				{
					material.SetInt("_ZWrite", 1);
				}
				material.DisableKeyword("_SURFACE_TYPE_TRANSPARENT");
				material.DisableKeyword("_ALPHABLEND_ON");
				material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
				material.renderQueue = -1;
			}
		}
	}
	internal sealed class RootboundTriangleProjectile : MonoBehaviour
	{
		private static readonly FieldRef<Projectile, Character> Owner = AccessTools.FieldRefAccess<Projectile, Character>("m_owner");

		private static readonly FieldRef<Projectile, Vector3> Velocity = AccessTools.FieldRefAccess<Projectile, Vector3>("m_vel");

		private static readonly FieldRef<Projectile, Vector3> StartPoint = AccessTools.FieldRefAccess<Projectile, Vector3>("m_startPoint");

		private static int _sequence;

		private Projectile _projectile;

		private bool _placed;

		private void Awake()
		{
			_projectile = ((Component)this).GetComponent<Projectile>();
		}

		private void Update()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//