Decompiled source of Beastkeeper v0.3.0

plugins/Beastkeeper/Beastkeeper.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace Beastkeeper;

[HarmonyPatch]
internal static class Bags
{
	private static readonly Dictionary<string, Vector2Int> Size = new Dictionary<string, Vector2Int>(StringComparer.OrdinalIgnoreCase)
	{
		{
			"Deer",
			new Vector2Int(5, 2)
		},
		{
			"Lox",
			new Vector2Int(6, 3)
		}
	};

	private static readonly MethodInfo DropAll = AccessTools.Method(typeof(Container), "DropAllItems", new Type[0], (Type[])null);

	private static Sprite _bkg;

	internal static bool IsPacker(Character c)
	{
		if ((Object)(object)c != (Object)null)
		{
			return Size.ContainsKey(Mount.Kind(((Component)c).gameObject));
		}
		return false;
	}

	private static Container Of(Character c)
	{
		Transform val = (((Object)(object)c != (Object)null) ? ((Component)c).transform.Find("Beastkeeper_Bags") : null);
		if (!((Object)(object)val != (Object)null))
		{
			return null;
		}
		return ((Component)val).GetComponent<Container>();
	}

	internal static void Attach(Character c)
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Expected O, but got Unknown
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Expected O, but got Unknown
		if (!((Object)(object)c == (Object)null) && Size.TryGetValue(Mount.Kind(((Component)c).gameObject), out var value))
		{
			ZNetView val = Leash.View((Component)(object)c);
			if (!((Object)(object)val == (Object)null) && val.GetZDO() != null && !((Object)(object)Of(c) != (Object)null))
			{
				GameObject val2 = new GameObject("Beastkeeper_Bags");
				val2.SetActive(false);
				val2.transform.SetParent(((Component)c).transform, false);
				Container val3 = val2.AddComponent<Container>();
				val3.m_name = "Saddle bags";
				val3.m_width = ((Vector2Int)(ref value)).x;
				val3.m_height = ((Vector2Int)(ref value)).y;
				val3.m_rootObjectOverride = val;
				val3.m_privacy = (PrivacySetting)2;
				val3.m_checkGuardStone = false;
				val3.m_autoDestroyEmpty = false;
				val3.m_defaultItems = new DropTable();
				val3.m_bkg = Background();
				val2.SetActive(true);
			}
		}
	}

	private static Sprite Background()
	{
		if ((Object)(object)_bkg != (Object)null || (Object)(object)ZNetScene.instance == (Object)null)
		{
			return _bkg;
		}
		GameObject prefab = ZNetScene.instance.GetPrefab("piece_chest_wood");
		Container val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Container>() : null);
		return _bkg = (((Object)(object)val != (Object)null) ? val.m_bkg : null);
	}

	internal static bool Empty(Character c)
	{
		Container val = Of(c);
		if (!((Object)(object)val == (Object)null) && val.GetInventory() != null)
		{
			return val.GetInventory().NrOfItems() == 0;
		}
		return true;
	}

	internal static void Open(Player p, Character c)
	{
		if (!IsPacker(c))
		{
			return;
		}
		Container val = Of(c);
		if ((Object)(object)val == (Object)null)
		{
			((Character)p).Message((MessageType)2, "These bags aren't ready yet.", 0, (Sprite)null, false);
			return;
		}
		if ((Object)(object)val.m_bkg == (Object)null)
		{
			val.m_bkg = Background();
		}
		val.Interact((Humanoid)(object)p, false, false);
		Plugin.Debug("[bags] opening " + ((Object)c).name + "'s bags (" + val.m_width + "x" + val.m_height + ")");
	}

	internal static void SpillNow(Character c)
	{
		Container val = Of(c);
		if (!((Object)(object)val == (Object)null) && !Empty(c) && !(DropAll == null))
		{
			DropAll.Invoke(val, null);
		}
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(Character), "OnDeath")]
	private static void Spill(Character __instance)
	{
		if (Plugin.Enabled.Value && IsPacker(__instance))
		{
			ZNetView val = Leash.View((Component)(object)__instance);
			Container val2 = Of(__instance);
			if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner() && !((Object)(object)val2 == (Object)null) && !Empty(__instance) && !(DropAll == null))
			{
				DropAll.Invoke(val2, null);
				Plugin.Debug("[bags] " + ((Object)__instance).name + " died: bags spilled");
			}
		}
	}
}
internal static class Breed
{
	private const float FedMinutes = 10f;

	private const float PregnantSeconds = 90f;

	private const float GrowMinutes = 30f;

	private const float CheckEvery = 10f;

	private const float Chance = 0.3f;

	private const int MaxHares = 12;

	private const float GlowChance = 0.08f;

	internal static readonly int ColorKey = StringExtensionMethods.GetStableHashCode("Beastkeeper_hue");

	internal static readonly int SatKey = StringExtensionMethods.GetStableHashCode("Beastkeeper_sat");

	internal static readonly int ValKey = StringExtensionMethods.GetStableHashCode("Beastkeeper_val");

	internal static readonly int GlowKey = StringExtensionMethods.GetStableHashCode("Beastkeeper_glow");

	internal static readonly int BornKey = StringExtensionMethods.GetStableHashCode("Beastkeeper_born");

	private static readonly int DueKey = StringExtensionMethods.GetStableHashCode("Beastkeeper_due");

	internal static bool IsHare(Character c)
	{
		if ((Object)(object)c != (Object)null)
		{
			return string.Equals(Mount.Kind(((Component)c).gameObject), "Hare", StringComparison.OrdinalIgnoreCase);
		}
		return false;
	}

	internal static void Attach(Character c)
	{
		if (IsHare(c) && (Object)(object)((Component)c).GetComponent<HareLook>() == (Object)null)
		{
			((Component)c).gameObject.AddComponent<HareLook>();
		}
	}

	internal static float Now()
	{
		if (!((Object)(object)ZNet.instance != (Object)null))
		{
			return Time.time;
		}
		return (float)ZNet.instance.GetTimeSeconds();
	}

	internal static float Grown(ZDO z)
	{
		float num = z.GetFloat(BornKey, 0f);
		if (num <= 0f)
		{
			return 1f;
		}
		return Mathf.Clamp01((Now() - num) / 1800f);
	}

	private static bool Ready(Character c)
	{
		ZNetView val = Leash.View((Component)(object)c);
		if ((Object)(object)c == (Object)null || c.IsDead() || !c.IsTamed() || (Object)(object)val == (Object)null || !val.IsValid())
		{
			return false;
		}
		if (Grown(val.GetZDO()) >= 1f)
		{
			return Feed.FedWithin(c, 600f);
		}
		return false;
	}

	internal static void Tick(Character c, ZNetView nv)
	{
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		ZDO zDO = nv.GetZDO();
		float num = zDO.GetFloat(DueKey, 0f);
		if (num > 0f)
		{
			if (Now() >= num)
			{
				zDO.Set(DueKey, 0f);
				Birth(c);
			}
		}
		else
		{
			if (!Ready(c) || Random.value > 0.3f)
			{
				return;
			}
			Character val = null;
			int num2 = 0;
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if (!((Object)(object)allCharacter == (Object)null) && !((Object)(object)allCharacter == (Object)(object)c) && IsHare(allCharacter) && !allCharacter.IsDead())
				{
					float num3 = Vector3.Distance(((Component)allCharacter).transform.position, ((Component)c).transform.position);
					if (num3 < 30f)
					{
						num2++;
					}
					if (num3 < 4f && (Object)(object)val == (Object)null && Ready(allCharacter))
					{
						val = allCharacter;
					}
				}
			}
			if (!((Object)(object)val == (Object)null) && num2 + 1 < 12)
			{
				zDO.Set(DueKey, Now() + 90f);
				Effect("m_loveEffects", ((Component)c).transform.position);
				Plugin.Debug("[breed] " + ((Object)c).name + " and a partner: a baby on the way (" + (num2 + 1) + " hares around)");
			}
		}
	}

	private static void Birth(Character mother)
	{
		//IL_002a: 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_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0049: 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_006b: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: 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)
		GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("Hare") : null);
		if (!((Object)(object)val == (Object)null))
		{
			Vector2 insideUnitCircle = Random.insideUnitCircle;
			Vector2 val2 = ((Vector2)(ref insideUnitCircle)).normalized * 0.8f;
			Vector3 val3 = ((Component)mother).transform.position + new Vector3(val2.x, 0.2f, val2.y);
			ZNetView val4 = Leash.View((Component)(object)mother);
			Vector3 val5 = (((Object)(object)val4 != (Object)null && val4.IsValid()) ? val4.GetZDO().GetVec3(Home.HomeKey, Vector3.zero) : Vector3.zero);
			SpawnBaby(val3, (val5 != Vector3.zero) ? val5 : val3);
		}
	}

	internal static void SpawnBaby(Vector3 at, Vector3 home, bool forceGlow = false)
	{
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("Hare") : null);
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		GameObject val2 = Object.Instantiate<GameObject>(val, at, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f));
		Character component = val2.GetComponent<Character>();
		ZNetView component2 = val2.GetComponent<ZNetView>();
		if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null) && component2.IsValid())
		{
			ZDO zDO = component2.GetZDO();
			zDO.Set(ColorKey, Random.value);
			zDO.Set(SatKey, (Random.value < 0.3f) ? Random.Range(0f, 0.12f) : Random.Range(0.25f, 1f));
			zDO.Set(ValKey, Random.Range(0.25f, 1.45f));
			if (forceGlow || Random.value < 0.08f)
			{
				zDO.Set(GlowKey, 1, false);
			}
			zDO.Set(BornKey, Now());
			zDO.Set(Halter.Key, 1, false);
			component.SetTamed(true);
			Home.Set(component, home);
			Effect("m_birthEffects", at);
			Plugin.Debug("[breed] a baby hare is born, colour " + zDO.GetFloat(ColorKey, -1f).ToString("0.00") + ((zDO.GetInt(GlowKey, 0) == 1) ? ", and it glows" : ""));
		}
	}

	private static void Effect(string field, Vector3 at)
	{
		//IL_005d: 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_006c: 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)
		GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("Boar") : null);
		Procreation val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Procreation>() : null);
		if (!((Object)(object)val2 == (Object)null))
		{
			EffectList val3 = ((field == "m_loveEffects") ? val2.m_loveEffects : val2.m_birthEffects);
			if (val3 != null)
			{
				val3.Create(at, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
			}
		}
	}
}
internal class HareLook : MonoBehaviour
{
	private Character _c;

	private ZNetView _nv;

	private Vector3 _baseScale;

	private float _hue = -2f;

	private float _sat;

	private float _val;

	private float _next;

	private float _nextBreed;

	private MaterialPropertyBlock _block;

	private bool _glowSet;

	private Light _light;

	private float _pulse;

	private readonly List<Material> _own = new List<Material>();

	private void Glow(float hue, float sat)
	{
		//IL_0020: 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_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Expected O, but got Unknown
		//IL_0167: 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_019a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0101: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
		Color val = ((sat < 0.15f) ? Color.white : Color.HSVToRGB(hue, Mathf.Max(0.5f, sat), 1f));
		Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true);
		foreach (Renderer val2 in componentsInChildren)
		{
			if (!(val2 is SkinnedMeshRenderer) && !(val2 is MeshRenderer))
			{
				continue;
			}
			Material[] materials = val2.materials;
			Material[] array = materials;
			foreach (Material val3 in array)
			{
				_own.Add(val3);
				if (!val3.HasProperty("_EmissionColor"))
				{
					Plugin.Debug("[breed] hare shader " + ((Object)val3.shader).name + " has no glow: light only");
					continue;
				}
				Texture2D val4 = HareSkin.GlowFor(val, val3.mainTexture);
				val3.EnableKeyword("_EMISSION");
				if ((Object)(object)val4 != (Object)null && val3.HasProperty("_EmissionMap"))
				{
					val3.SetTexture("_EmissionMap", (Texture)(object)val4);
					val3.SetColor("_EmissionColor", Color.white * 2f);
				}
				else
				{
					val3.SetColor("_EmissionColor", val * 0.6f);
				}
				val3.globalIlluminationFlags = (MaterialGlobalIlluminationFlags)1;
			}
			val2.materials = materials;
		}
		GameObject val5 = new GameObject("Beastkeeper_HareGlow");
		val5.transform.SetParent(((Component)this).transform, false);
		val5.transform.localPosition = Vector3.up * 0.4f;
		_light = val5.AddComponent<Light>();
		_light.type = (LightType)2;
		_light.color = val;
		_light.range = 3f;
		_light.intensity = 0.8f;
		_light.shadows = (LightShadows)0;
		_pulse = Random.Range(0f, 10f);
	}

	private void LateUpdate()
	{
		if (!((Object)(object)_light == (Object)null))
		{
			_pulse += Time.deltaTime;
			_light.intensity = 0.55f + 0.35f * Mathf.Sin(_pulse * 1.6f);
		}
	}

	private void OnDestroy()
	{
		foreach (Material item in _own)
		{
			if ((Object)(object)item != (Object)null)
			{
				Object.Destroy((Object)(object)item);
			}
		}
	}

	private void Awake()
	{
		//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)
		_c = ((Component)this).GetComponent<Character>();
		_nv = ((Component)this).GetComponent<ZNetView>();
		_baseScale = ((Component)this).transform.localScale;
		_nextBreed = Time.time + Random.Range(2f, 10f);
	}

	private void Update()
	{
		//IL_00f3: 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)
		if (!(Time.time < _next) && !((Object)(object)_nv == (Object)null) && _nv.IsValid() && Plugin.Enabled.Value)
		{
			_next = Time.time + 1f;
			ZDO zDO = _nv.GetZDO();
			float num = zDO.GetFloat(Breed.ColorKey, -1f);
			float num2 = zDO.GetFloat(Breed.SatKey, 0.55f);
			float num3 = zDO.GetFloat(Breed.ValKey, 1f);
			if (num != _hue || num2 != _sat || num3 != _val)
			{
				_hue = num;
				_sat = num2;
				_val = num3;
				Paint(num, num2, num3);
			}
			if (!_glowSet && num >= 0f && zDO.GetInt(Breed.GlowKey, 0) == 1)
			{
				_glowSet = true;
				Glow(num, num2);
			}
			((Component)this).transform.localScale = _baseScale * Mathf.Lerp(0.5f, 1f, Breed.Grown(zDO));
			if (_nv.IsOwner() && Time.time >= _nextBreed)
			{
				_nextBreed = Time.time + 10f;
				Breed.Tick(_c, _nv);
			}
		}
	}

	private void Paint(float hue, float sat, float val)
	{
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		if (hue < 0f)
		{
			return;
		}
		if (_block == null)
		{
			_block = new MaterialPropertyBlock();
		}
		Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true);
		foreach (Renderer val2 in componentsInChildren)
		{
			if (val2 is SkinnedMeshRenderer || val2 is MeshRenderer)
			{
				Material sharedMaterial = val2.sharedMaterial;
				Texture2D val3 = HareSkin.For(hue, sat, val, ((Object)(object)sharedMaterial != (Object)null) ? sharedMaterial.mainTexture : null);
				val2.GetPropertyBlock(_block);
				if ((Object)(object)val3 != (Object)null)
				{
					_block.SetTexture("_MainTex", (Texture)(object)val3);
				}
				else
				{
					_block.SetColor("_Color", Color.HSVToRGB(hue, 0.5f, 1f));
				}
				val2.SetPropertyBlock(_block);
			}
		}
	}
}
[HarmonyPatch]
internal static class Census
{
	private static bool _done;

	[HarmonyPostfix]
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	[HarmonyPriority(0)]
	private static void List(ZNetScene __instance)
	{
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Invalid comparison between Unknown and I4
		//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
		if (_done || !Plugin.DetailedLog.Value)
		{
			return;
		}
		_done = true;
		StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.AppendLine("[census] prefab | name | faction | boss | ai | tame | height | ride");
		foreach (GameObject prefab in __instance.m_prefabs)
		{
			if (!((Object)(object)prefab == (Object)null))
			{
				Character component = prefab.GetComponent<Character>();
				if (!((Object)(object)component == (Object)null) && !(component is Player))
				{
					string name = ((Object)prefab).name;
					bool flag = (Object)(object)prefab.GetComponent<Tameable>() != (Object)null;
					string text = (((Object)(object)prefab.GetComponent<AnimalAI>() != (Object)null) ? "AnimalAI" : (((Object)(object)prefab.GetComponent<MonsterAI>() != (Object)null) ? "MonsterAI" : "none"));
					bool flag2 = !component.m_boss && !Has(Plugin.NotAnimals.Value, name) && (flag || text == "AnimalAI" || (int)component.m_faction == 1 || Has(Plugin.ExtraAnimals.Value, name));
					string text2 = ((!flag2) ? "no" : (flag ? "game" : "halter"));
					float num = Height(prefab);
					string text3 = ((!flag2) ? "no" : (Has(Plugin.NotRideable.Value, name) ? "blocked" : ((num >= Plugin.RideMinHeight.Value) ? "yes" : "too small")));
					string text4 = ((Localization.instance != null) ? Localization.instance.Localize(component.m_name) : component.m_name);
					stringBuilder.AppendLine(string.Concat("[census] ", name, " | ", text4, " | ", component.m_faction, " | ", component.m_boss ? "boss" : "-", " | ", text, " | ", text2, " | ", num.ToString("0.00"), " | ", text3));
				}
			}
		}
		Plugin.Log.LogInfo((object)stringBuilder.ToString());
	}

	private static float Height(GameObject g)
	{
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: 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_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: 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)
		Collider val = g.GetComponent<Collider>();
		if ((Object)(object)val == (Object)null)
		{
			val = g.GetComponentInChildren<Collider>(true);
		}
		if ((Object)(object)val == (Object)null)
		{
			return 0f;
		}
		float y = ((Component)val).transform.lossyScale.y;
		float num = 0f;
		CapsuleCollider val2 = (CapsuleCollider)(object)((val is CapsuleCollider) ? val : null);
		BoxCollider val3 = (BoxCollider)(object)((val is BoxCollider) ? val : null);
		SphereCollider val4 = (SphereCollider)(object)((val is SphereCollider) ? val : null);
		if ((Object)(object)val2 != (Object)null)
		{
			num = val2.center.y + val2.height / 2f;
		}
		else if ((Object)(object)val3 != (Object)null)
		{
			num = val3.center.y + val3.size.y / 2f;
		}
		else if ((Object)(object)val4 != (Object)null)
		{
			num = val4.center.y + val4.radius;
		}
		Vector3 val5 = default(Vector3);
		((Vector3)(ref val5))..ctor(0f, num, 0f);
		return (((Component)val).transform.position + ((Component)val).transform.rotation * Vector3.Scale(val5, ((Component)val).transform.lossyScale)).y - g.transform.position.y + 0f * y;
	}

	private static bool Has(string list, string prefab)
	{
		if (string.IsNullOrEmpty(list))
		{
			return false;
		}
		string[] array = list.Split(',');
		foreach (string text in array)
		{
			if (string.Equals(text.Trim(), prefab, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
		}
		return false;
	}
}
internal static class Compat
{
	private const string Impactful = "MidnightsFX.ImpactfulSkills";

	internal static void Init()
	{
		((MonoBehaviour)Plugin.Instance).StartCoroutine(Later());
	}

	private static IEnumerator Later()
	{
		yield return null;
		if (Plugin.Enabled.Value && Chainloader.PluginInfos.TryGetValue("MidnightsFX.ImpactfulSkills", out var info) && !((Object)(object)info.Instance == (Object)null))
		{
			ConfigFile cfg = info.Instance.Config;
			Set(cfg, "AnimalTamingSpeedFactor", 1f);
			Set(cfg, "EnableTamingHandFeeding", false);
			Set(cfg, "EnableTamingProgressDisplay", false);
		}
	}

	private static void Set(ConfigFile cfg, string key, object value)
	{
		foreach (ConfigDefinition key2 in cfg.Keys)
		{
			if (!(key2.Key != key))
			{
				ConfigEntryBase val = cfg[key2];
				if (!object.Equals(val.BoxedValue, value))
				{
					val.BoxedValue = value;
					Plugin.Debug(string.Concat("[compat] Impactful Skills: ", key, " set to ", value, " (only the halter tames)"));
				}
				break;
			}
		}
	}
}
internal static class Defend
{
	private class Look
	{
		public bool Threat;

		public float Until;
	}

	private static readonly Dictionary<Character, Look> Looks = new Dictionary<Character, Look>();

	private static readonly Dictionary<Character, bool> Fighters = new Dictionary<Character, bool>();

	internal static bool CanFight(Character c)
	{
		if (Fighters.TryGetValue(c, out var value))
		{
			return value;
		}
		value = false;
		Humanoid val = (Humanoid)(object)((c is Humanoid) ? c : null);
		if ((Object)(object)val != (Object)null && val.GetInventory() != null)
		{
			foreach (ItemData allItem in val.GetInventory().GetAllItems())
			{
				if (allItem != null && allItem.IsWeapon() && allItem.m_shared.m_attack != null && !string.IsNullOrEmpty(allItem.m_shared.m_attack.m_attackAnimation))
				{
					value = true;
					break;
				}
			}
		}
		if (Fighters.Count > 300)
		{
			Fighters.Clear();
		}
		Fighters[c] = value;
		return value;
	}

	internal static bool Active(BaseAI ai, Character c, Vector3? post)
	{
		//IL_0138: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_014c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0151: Unknown result type (might be due to invalid IL or missing references)
		if (!Plugin.TamedDefend.Value || !(ai is MonsterAI) || (Object)(object)c == (Object)null || !c.IsTamed() || Sea.IsSeaMount(c) || !CanFight(c))
		{
			return false;
		}
		if (Looks.TryGetValue(c, out var value) && Time.time < value.Until)
		{
			return value.Threat;
		}
		if (value == null)
		{
			value = new Look();
			Looks[c] = value;
			if (Looks.Count > 300)
			{
				Looks.Clear();
			}
		}
		value.Until = Time.time + 0.75f;
		value.Threat = false;
		float value2 = Plugin.DefendRange.Value;
		foreach (Character allCharacter in Character.GetAllCharacters())
		{
			if ((Object)(object)allCharacter == (Object)null || (Object)(object)allCharacter == (Object)(object)c || allCharacter.IsDead() || allCharacter.IsPlayer() || allCharacter.IsTamed())
			{
				continue;
			}
			BaseAI baseAI = allCharacter.GetBaseAI();
			if (!((Object)(object)baseAI == (Object)null) && !(baseAI is AnimalAI) && BaseAI.IsEnemy(c, allCharacter))
			{
				Vector3 val = (post.HasValue ? post.Value : ((Component)c).transform.position);
				Vector3 val2 = ((Component)allCharacter).transform.position - val;
				val2.y = 0f;
				float num = ((Vector3)(ref val2)).magnitude - (post.HasValue ? 4f : 0f);
				if (num <= value2)
				{
					value.Threat = true;
					break;
				}
			}
		}
		if (value.Threat)
		{
			Plugin.Debug("[defend] " + ((Object)c).name + " sees a threat: it fights");
		}
		return value.Threat;
	}
}
[HarmonyPatch]
[HarmonyPatch]
internal static class Drake
{
	private class Shot
	{
		internal ItemData Item;

		internal Attack Attack;

		internal GameObject Prefab;

		internal bool AtTarget;

		internal string From;
	}

	internal class Palette
	{
		internal Color? Scales;

		internal Color? Wings;

		internal Color? Horns;

		internal Color? Eyes;

		internal Color Glow = Color.white;
	}

	private const float LowAltitude = 3f;

	private const float ClimbShare = 0.7f;

	private const float LandAt = 1.2f;

	private const float BurstSlow = 0.5f;

	private const float BurstSeconds = 1.6f;

	private const float BurstEvery = 0.16f;

	internal const int Frost = 1;

	internal const int Fire = 2;

	internal const int Poison = 3;

	internal const int Earth = 4;

	internal const int Lightning = 5;

	private const float BabyShare = 0.4f;

	private static readonly int AirKey = StringExtensionMethods.GetStableHashCode("Beastkeeper_air");

	private static readonly int AirAtKey = StringExtensionMethods.GetStableHashCode("Beastkeeper_airAt");

	private static float _air;

	private static bool _tired;

	private static float _slow = -1f;

	private static float _fast = -1f;

	private static bool _onFoot;

	private static float _jog0 = -1f;

	private static float _run0 = -1f;

	private static Character _speedOf;

	private static float _nextSave;

	internal static float OffAt = -100f;

	private static float _nextSay;

	private static readonly Dictionary<string, Dictionary<string, Matrix4x4>> Rest = new Dictionary<string, Dictionary<string, Matrix4x4>>();

	private static GameObject _bar;

	private static GuiBar[] _fills;

	private static readonly Dictionary<int, Shot> Shots = new Dictionary<int, Shot>();

	private static GameObject _strike;

	private static bool _strikeLooked;

	private static float _nextShot;

	internal static bool Aiming;

	private static Character _pending;

	private static Player _pendingRider;

	private static float _startedAt;

	private static bool _launched;

	private static int _burstLeft;

	private static float _burstNext;

	private static float _burstEnd;

	private static Animator _slowed;

	private static float _slowedSpeed;

	private static Character _queuedC;

	private static Player _queuedRider;

	private static float _queuedAt;

	private static readonly Dictionary<Character, float> _dealt = new Dictionary<Character, float>();

	private static float _attackUntil;

	private static readonly HashSet<Projectile> _rocks = new HashSet<Projectile>();

	private static float _safeUntil;

	internal static readonly int ElementKey = StringExtensionMethods.GetStableHashCode("Beastkeeper_element");

	private static readonly int BornKey = StringExtensionMethods.GetStableHashCode("Beastkeeper_drakeBorn");

	internal static readonly int GlowKey = StringExtensionMethods.GetStableHashCode("Beastkeeper_drakeGlow");

	internal static int PaletteVersion;

	private static readonly Dictionary<int, Palette> Palettes = new Dictionary<int, Palette>();

	private static float Max => Mathf.Max(1f, Plugin.DrakeFlightSeconds.Value);

	internal static bool Tired => _tired;

	internal static string BabyPrefab
	{
		get
		{
			string[] array = (Plugin.DrakeMounts.Value ?? "").Split(',');
			foreach (string text in array)
			{
				if (text.Trim().Length > 0)
				{
					return text.Trim();
				}
			}
			return "Hatchling";
		}
	}

	internal static bool Is(Character c)
	{
		if ((Object)(object)c == (Object)null || Plugin.DrakeMounts == null)
		{
			return false;
		}
		string b = Mount.Kind(((Component)c).gameObject);
		string[] array = (Plugin.DrakeMounts.Value ?? "").Split(',');
		foreach (string text in array)
		{
			if (string.Equals(text.Trim(), b, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
		}
		return false;
	}

	internal static void KeepSize(Character c)
	{
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: 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)
		if (Is(c))
		{
			float num = ((c.IsTamed() && Plugin.Enabled.Value) ? (Plugin.DrakeSize.Value * Mathf.Lerp(0.4f, 1f, Grown(c))) : 1f);
			if (Mathf.Abs(((Component)c).transform.localScale.x - num) > 0.001f)
			{
				((Component)c).transform.localScale = Vector3.one * num;
			}
		}
	}

	internal static void OnRide(Character c)
	{
		KeepSafe(1f);
		KeepSize(c);
		ZNetView val = Leash.View((Component)(object)c);
		_air = Max;
		if ((Object)(object)val != (Object)null && val.IsValid())
		{
			ZDO zDO = val.GetZDO();
			float num = zDO.GetFloat(AirKey, Max);
			double num2 = (double)zDO.GetLong(AirAtKey, 0L) / 1000.0;
			float num3 = (((Object)(object)ZNet.instance != (Object)null && num2 > 0.0) ? ((float)(ZNet.instance.GetTimeSeconds() - num2)) : 0f);
			_air = Mathf.Clamp(num + Mathf.Max(0f, num3) * Max / Mathf.Max(1f, Plugin.DrakeRestSeconds.Value), 0f, Max);
		}
		_tired = _air < Max * 0.3f;
		_speedOf = c;
		_slow = c.m_flySlowSpeed;
		_fast = c.m_flyFastSpeed;
		_jog0 = c.m_speed;
		_run0 = c.m_runSpeed;
		_onFoot = Altitude(c) < 1.2f;
		if (_onFoot)
		{
			if (c.IsFlying())
			{
				c.Land();
			}
		}
		else if (!c.IsFlying())
		{
			c.TakeOff();
		}
		Plugin.Debug("[drake] on " + ((Object)c).name + ": flight " + _air.ToString("0") + "/" + Max.ToString("0") + " s, own speeds " + _slow.ToString("0.0") + "/" + _fast.ToString("0.0"));
	}

	internal static bool TakeOffToAttack(Character c)
	{
		if (!_onFoot && c.IsFlying())
		{
			return false;
		}
		if (_tired)
		{
			return false;
		}
		_onFoot = false;
		c.TakeOff();
		return true;
	}

	internal static void OnGetOff(Character c)
	{
		OffAt = Time.time;
		Save(c);
		if ((Object)(object)_speedOf == (Object)(object)c && _slow >= 0f)
		{
			c.m_flySlowSpeed = _slow;
			c.m_flyFastSpeed = _fast;
		}
		if (_jog0 >= 0f)
		{
			c.m_speed = _jog0;
			c.m_runSpeed = _run0;
		}
		_onFoot = false;
		_speedOf = null;
		if (c.IsFlying() && Altitude(c) < 3f)
		{
			c.Land();
		}
	}

	private static void Save(Character c)
	{
		ZNetView val = Leash.View((Component)(object)c);
		if (!((Object)(object)val == (Object)null) && val.IsValid() && val.IsOwner() && !((Object)(object)ZNet.instance == (Object)null))
		{
			val.GetZDO().Set(AirKey, _air);
			val.GetZDO().Set(AirAtKey, (long)(ZNet.instance.GetTimeSeconds() * 1000.0));
		}
	}

	[HarmonyPatch(typeof(Player), "StopDoodadControl")]
	[HarmonyPrefix]
	private static bool StayOn(Player __instance)
	{
		if (!Plugin.Enabled.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || ((Character)__instance).IsDead() || ((Character)__instance).IsTeleporting())
		{
			return true;
		}
		Mount mount = __instance.GetDoodadController() as Mount;
		Character val = Mount.RiddenCharacter();
		if ((Object)(object)mount == (Object)null || (Object)(object)mount != (Object)(object)Mount.Riding || (Object)(object)val == (Object)null || val.IsDead() || !Is(val))
		{
			return true;
		}
		if (!ZInput.GetButtonDown("Use") && !ZInput.GetButtonDown("JoyUse"))
		{
			return true;
		}
		if (_onFoot && !val.IsFlying())
		{
			return true;
		}
		((Character)__instance).Message((MessageType)2, "Land first to get off: fly down close to the ground and hold crouch.", 0, (Sprite)null, false);
		return false;
	}

	internal static float Altitude(Character c)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: 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_007d: 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)
		Vector3 position = ((Component)c).transform.position;
		float num = (((Object)(object)ZoneSystem.instance != (Object)null) ? ZoneSystem.instance.GetGroundHeight(position) : (position.y - 1000f));
		int mask = LayerMask.GetMask(new string[4] { "terrain", "Default", "static_solid", "piece" });
		RaycastHit val = default(RaycastHit);
		if (Physics.Raycast(position + Vector3.up * 0.2f, Vector3.down, ref val, 300f, mask, (QueryTriggerInteraction)1))
		{
			num = Mathf.Max(num, ((RaycastHit)(ref val)).point.y);
		}
		if ((Object)(object)ZoneSystem.instance != (Object)null)
		{
			num = Mathf.Max(num, ZoneSystem.instance.m_waterLevel);
		}
		return position.y - num;
	}

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

	internal static void Drive(Character c, Vector3 fwd, Vector3 move, bool run, float dt)
	{
		//IL_011d: 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_0136: Unknown result type (might be due to invalid IL or missing references)
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_031b: Unknown result type (might be due to invalid IL or missing references)
		//IL_031c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0334: Unknown result type (might be due to invalid IL or missing references)
		//IL_0339: Unknown result type (might be due to invalid IL or missing references)
		//IL_033e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0355: Unknown result type (might be due to invalid IL or missing references)
		//IL_0357: Unknown result type (might be due to invalid IL or missing references)
		//IL_035d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0367: Unknown result type (might be due to invalid IL or missing references)
		//IL_036c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0371: Unknown result type (might be due to invalid IL or missing references)
		//IL_0374: Unknown result type (might be due to invalid IL or missing references)
		//IL_0380: Unknown result type (might be due to invalid IL or missing references)
		bool flag = !Typing();
		float num = 0f;
		bool flag2 = flag && (ZInput.GetButton("Jump") || ZInput.GetButton("JoyJump"));
		bool flag3 = flag && (ZInput.GetButton("Crouch") || ZInput.GetButton("JoyCrouch"));
		if (flag2)
		{
			num += 1f;
		}
		if (flag3)
		{
			num -= 1f;
		}
		if (_onFoot)
		{
			if (!flag2 || _tired)
			{
				if (c.IsFlying())
				{
					c.Land();
				}
				_air = Mathf.Min(Max, _air + dt * Max / Mathf.Max(1f, Plugin.DrakeRestSeconds.Value));
				if (_tired && _air >= Max * 0.3f)
				{
					_tired = false;
					Say("Your drake has rested: it can fly again.");
				}
				c.m_speed = Plugin.DrakeGroundSpeed.Value;
				c.m_runSpeed = Plugin.DrakeGroundSprint.Value;
				Vector3 moveDir = Quaternion.LookRotation(fwd) * new Vector3(move.x, 0f, move.z);
				if (((Vector3)(ref moveDir)).sqrMagnitude > 1f)
				{
					((Vector3)(ref moveDir)).Normalize();
				}
				c.SetLookDir(fwd, 0f);
				c.SetMoveDir(moveDir);
				c.SetRun(run && ((Vector3)(ref moveDir)).sqrMagnitude > 0.01f);
				if (Time.time > _nextSave)
				{
					_nextSave = Time.time + 2f;
					Save(c);
				}
				return;
			}
			_onFoot = false;
			c.TakeOff();
			Say("Your drake takes off.");
		}
		if (!c.IsFlying())
		{
			c.TakeOff();
		}
		c.m_flySlowSpeed = Plugin.DrakeSpeed.Value;
		c.m_flyFastSpeed = Plugin.DrakeSprintSpeed.Value;
		float num2 = Altitude(c);
		bool flag4 = num2 > 3f;
		if (num2 < 1.2f && flag3)
		{
			_onFoot = true;
			c.Land();
			Say("Your drake lands. It walks now: jump to take off.");
			return;
		}
		if (flag4)
		{
			_air -= dt * (run ? 1.5f : 1f);
		}
		else if (num <= 0f)
		{
			_air += dt * Max / Mathf.Max(1f, Plugin.DrakeRestSeconds.Value);
		}
		_air = Mathf.Clamp(_air, 0f, Max);
		if (_air <= 0f && !_tired)
		{
			_tired = true;
			Say("Your drake is tired: it glides down to rest.");
		}
		if (_tired && _air >= Max * 0.3f)
		{
			_tired = false;
			Say("Your drake has rested: it can climb again.");
		}
		if (_tired)
		{
			num = ((!flag4) ? Mathf.Min(num, 0f) : (-0.6f));
		}
		float value = Plugin.DrakeMaxAltitude.Value;
		if (num2 > value + 4f)
		{
			num = Mathf.Min(num, -0.4f);
		}
		else if (num2 > value)
		{
			num = Mathf.Min(num, 0f);
		}
		Vector3 val = Quaternion.LookRotation(fwd) * new Vector3(move.x, 0f, move.z);
		if (((Vector3)(ref val)).sqrMagnitude > 1f)
		{
			((Vector3)(ref val)).Normalize();
		}
		Vector3 moveDir2 = val + Vector3.up * num * 0.7f;
		c.SetLookDir(fwd, 0f);
		c.SetMoveDir(moveDir2);
		c.SetRun(run && ((Vector3)(ref val)).sqrMagnitude > 0.01f);
		if (Time.time > _nextSave)
		{
			_nextSave = Time.time + 2f;
			Save(c);
		}
	}

	internal static bool MayAttack(Character c)
	{
		if (!Plugin.DrakeAttackInAir.Value)
		{
			return Altitude(c) < 4f;
		}
		return true;
	}

	internal static void Fed(Character c, ZNetView nv)
	{
		if (Is(c) && !((Object)(object)nv == (Object)null) && nv.IsValid() && !((Object)(object)ZNet.instance == (Object)null))
		{
			nv.GetZDO().Set(AirKey, Max);
			nv.GetZDO().Set(AirAtKey, (long)(ZNet.instance.GetTimeSeconds() * 1000.0));
			if ((Object)(object)Mount.RiddenCharacter() == (Object)(object)c)
			{
				_air = Max;
				_tired = false;
			}
		}
	}

	private static void Say(string s)
	{
		Player localPlayer = Player.m_localPlayer;
		if (!((Object)(object)localPlayer == (Object)null) && !(Time.time < _nextSay))
		{
			_nextSay = Time.time + 1f;
			((Character)localPlayer).Message((MessageType)2, s, 0, (Sprite)null, false);
		}
	}

	internal static GameObject PosedCopy(GameObject prefab, out GameObject holder)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_002a: 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_007b: Expected O, but got Unknown
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Expected O, but got Unknown
		//IL_0111: 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_0143: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_030b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0311: Invalid comparison between Unknown and I4
		holder = new GameObject("Beastkeeper_PoseTmp");
		holder.SetActive(false);
		holder.transform.position = new Vector3(0f, -5000f, 0f);
		Animator componentInChildren = prefab.GetComponentInChildren<Animator>(true);
		if ((Object)(object)componentInChildren == (Object)null || (Object)(object)((Component)componentInChildren).gameObject == (Object)(object)prefab)
		{
			Plugin.Debug("[drake] " + ((Object)prefab).name + ": no model part to pose");
			return null;
		}
		GameObject val = new GameObject(((Object)prefab).name);
		val.transform.SetParent(holder.transform, false);
		Transform transform = val.transform;
		List<Transform> list = new List<Transform>();
		Transform parent = ((Component)componentInChildren).transform.parent;
		while ((Object)(object)parent != (Object)null && (Object)(object)parent != (Object)(object)prefab.transform)
		{
			list.Add(parent);
			parent = parent.parent;
		}
		for (int num = list.Count - 1; num >= 0; num--)
		{
			GameObject val2 = new GameObject(((Object)list[num]).name);
			val2.transform.SetParent(transform, false);
			val2.transform.localPosition = list[num].localPosition;
			val2.transform.localRotation = list[num].localRotation;
			val2.transform.localScale = list[num].localScale;
			transform = val2.transform;
		}
		GameObject val3 = Object.Instantiate<GameObject>(((Component)componentInChildren).gameObject, transform, false);
		((Object)val3).name = ((Object)((Component)componentInChildren).gameObject).name;
		val3.transform.localPosition = ((Component)componentInChildren).transform.localPosition;
		val3.transform.localRotation = ((Component)componentInChildren).transform.localRotation;
		val3.transform.localScale = ((Component)componentInChildren).transform.localScale;
		MonoBehaviour[] componentsInChildren = val3.GetComponentsInChildren<MonoBehaviour>(true);
		foreach (MonoBehaviour val4 in componentsInChildren)
		{
			Object.DestroyImmediate((Object)(object)val4);
		}
		if ((Object)(object)val3.GetComponentInChildren<Character>(true) != (Object)null)
		{
			Plugin.Log.LogWarning((object)("[drake] model part of " + ((Object)prefab).name + " is a creature: not posed"));
			return null;
		}
		AudioSource[] componentsInChildren2 = val3.GetComponentsInChildren<AudioSource>(true);
		foreach (AudioSource val5 in componentsInChildren2)
		{
			Object.DestroyImmediate((Object)(object)val5);
		}
		Light[] componentsInChildren3 = val3.GetComponentsInChildren<Light>(true);
		foreach (Light val6 in componentsInChildren3)
		{
			Object.DestroyImmediate((Object)(object)val6);
		}
		Collider[] componentsInChildren4 = val3.GetComponentsInChildren<Collider>(true);
		foreach (Collider val7 in componentsInChildren4)
		{
			Object.DestroyImmediate((Object)(object)val7);
		}
		Rigidbody[] componentsInChildren5 = val3.GetComponentsInChildren<Rigidbody>(true);
		foreach (Rigidbody val8 in componentsInChildren5)
		{
			Object.DestroyImmediate((Object)(object)val8);
		}
		holder.SetActive(true);
		Animator component = val3.GetComponent<Animator>();
		if ((Object)(object)component != (Object)null)
		{
			component.cullingMode = (AnimatorCullingMode)0;
			AnimatorControllerParameter[] parameters = component.parameters;
			foreach (AnimatorControllerParameter val9 in parameters)
			{
				if ((int)val9.type == 4 && val9.name == "flying")
				{
					component.SetBool("flying", true);
				}
			}
			for (int num2 = 0; num2 < 30; num2++)
			{
				component.Update(0.1f);
			}
			Plugin.Debug("[drake] posed " + ((Object)prefab).name + " in its flying pose");
		}
		else
		{
			Plugin.Debug("[drake] " + ((Object)prefab).name + " has no animator: built pose");
		}
		return val;
	}

	private static string PathOf(Transform root, Transform t)
	{
		string text = "";
		Transform val = t;
		while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root)
		{
			text = ((text.Length == 0) ? ((Object)val).name : (((Object)val).name + "/" + text));
			val = val.parent;
		}
		return text;
	}

	internal static bool RestOf(Character c, Transform bone, out Matrix4x4 m)
	{
		//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_007f: 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_00ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		m = Matrix4x4.identity;
		if (!Is(c) || (Object)(object)bone == (Object)null || (Object)(object)ZNetScene.instance == (Object)null)
		{
			return false;
		}
		string prefabName = Utils.GetPrefabName(((Component)c).gameObject);
		if (!Rest.TryGetValue(prefabName, out var value))
		{
			value = new Dictionary<string, Matrix4x4>();
			GameObject prefab = ZNetScene.instance.GetPrefab(prefabName);
			if ((Object)(object)prefab != (Object)null)
			{
				GameObject holder;
				GameObject val = PosedCopy(prefab, out holder);
				try
				{
					if ((Object)(object)val != (Object)null)
					{
						Matrix4x4 worldToLocalMatrix = val.transform.worldToLocalMatrix;
						Transform[] componentsInChildren = val.GetComponentsInChildren<Transform>(true);
						foreach (Transform val2 in componentsInChildren)
						{
							value[PathOf(val.transform, val2)] = worldToLocalMatrix * val2.localToWorldMatrix;
						}
					}
				}
				finally
				{
					Object.Destroy((Object)(object)holder);
				}
			}
			Rest[prefabName] = value;
		}
		return value.TryGetValue(PathOf(((Component)c).transform, bone), out m);
	}

	internal static void UpdateBar()
	{
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_0123: Unknown result type (might be due to invalid IL or missing references)
		//IL_0132: Unknown result type (might be due to invalid IL or missing references)
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		Character val = Mount.RiddenCharacter();
		if (!((Object)(object)val != (Object)null) || !Is(val) || !((Object)(object)Hud.instance != (Object)null))
		{
			if ((Object)(object)_bar != (Object)null && _bar.activeSelf)
			{
				_bar.SetActive(false);
			}
		}
		else
		{
			if ((Object)(object)_bar == (Object)null && !MakeBar())
			{
				return;
			}
			if (!_bar.activeSelf)
			{
				_bar.SetActive(true);
			}
			float value = _air / Max;
			Color color = (_tired ? new Color(0.85f, 0.35f, 0.3f) : new Color(0.55f, 0.85f, 1f));
			GuiBar[] fills = _fills;
			foreach (GuiBar val2 in fills)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					val2.SetValue(value);
					val2.SetColor(color);
				}
			}
			RectTransform staminaBar2Root = Hud.instance.m_staminaBar2Root;
			RectTransform component = _bar.GetComponent<RectTransform>();
			if ((Object)(object)staminaBar2Root != (Object)null && (Object)(object)component != (Object)null)
			{
				component.anchoredPosition = staminaBar2Root.anchoredPosition + new Vector2(0f, 46f);
			}
		}
	}

	private static bool MakeBar()
	{
		//IL_0132: Unknown result type (might be due to invalid IL or missing references)
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Unknown result type (might be due to invalid IL or missing references)
		RectTransform staminaBar2Root = Hud.instance.m_staminaBar2Root;
		if ((Object)(object)staminaBar2Root == (Object)null)
		{
			return false;
		}
		_bar = Object.Instantiate<GameObject>(((Component)staminaBar2Root).gameObject, ((Transform)staminaBar2Root).parent, false);
		((Object)_bar).name = "Beastkeeper_DrakeFlight";
		Animator[] componentsInChildren = _bar.GetComponentsInChildren<Animator>(true);
		foreach (Animator val in componentsInChildren)
		{
			Object.Destroy((Object)(object)val);
		}
		TMP_Text[] componentsInChildren2 = _bar.GetComponentsInChildren<TMP_Text>(true);
		foreach (TMP_Text val2 in componentsInChildren2)
		{
			((Component)val2).gameObject.SetActive(false);
		}
		CanvasGroup[] componentsInChildren3 = _bar.GetComponentsInChildren<CanvasGroup>(true);
		foreach (CanvasGroup val3 in componentsInChildren3)
		{
			val3.alpha = 1f;
		}
		Transform[] componentsInChildren4 = _bar.GetComponentsInChildren<Transform>(true);
		foreach (Transform val4 in componentsInChildren4)
		{
			if ((Object)(object)((Component)val4).GetComponent<TMP_Text>() == (Object)null)
			{
				((Component)val4).gameObject.SetActive(true);
			}
		}
		Graphic[] componentsInChildren5 = _bar.GetComponentsInChildren<Graphic>(true);
		foreach (Graphic val5 in componentsInChildren5)
		{
			if (!(val5 is TMP_Text))
			{
				Color color = val5.color;
				color.a = 1f;
				val5.color = color;
				((Behaviour)val5).enabled = true;
			}
		}
		_fills = _bar.GetComponentsInChildren<GuiBar>(true);
		Plugin.Debug("[drake] flight bar made (" + _fills.Length + " fills)");
		return true;
	}

	private static bool IsStream(int el)
	{
		if (el != 2)
		{
			return el == 3;
		}
		return true;
	}

	private static string[] SourcesOf(int el)
	{
		return el switch
		{
			4 => new string[1] { "creature:Troll" }, 
			2 => new string[4] { "item:StaffFireball", "projectile:GoblinShaman_projectile_fireball", "projectile:Imp_fireball_projectile", "creature:Fenring_Cultist" }, 
			3 => new string[4] { "creature:Greydwarf_Shaman", "projectile:*poison*", "projectile:*acid*", "projectile:*spit*" }, 
			5 => new string[3] { "creature:Eikthyr", "item:StaffLightning", "item:*lightning*" }, 
			_ => new string[1] { "creature:" + BabyPrefab }, 
		};
	}

	private static Shot ShotOf(int el)
	{
		if (Shots.TryGetValue(el, out var value))
		{
			return value;
		}
		value = null;
		string[] array = SourcesOf(el);
		foreach (string src in array)
		{
			value = Find(src, el);
			if (value != null)
			{
				break;
			}
		}
		if (value == null && el != 1)
		{
			value = ShotOf(1);
		}
		if ((Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ObjectDB.instance != (Object)null)
		{
			Shots[el] = value;
		}
		Plugin.Debug("[drake] " + ElementName(el) + " attack: " + ((value != null) ? (value.From + " (" + (value.AtTarget ? "at target " : "") + ((Object)value.Prefab).name + ")") : "none found"));
		return value;
	}

	private static List<GameObject> ItemsOf(string src)
	{
		List<GameObject> list = new List<GameObject>();
		if (src.StartsWith("creature:"))
		{
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(src.Substring(9)) : null);
			Humanoid val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<Humanoid>() : null);
			if ((Object)(object)val2 == (Object)null)
			{
				return list;
			}
			if (val2.m_defaultItems != null)
			{
				list.AddRange(val2.m_defaultItems);
			}
			if (val2.m_randomWeapon != null)
			{
				list.AddRange(val2.m_randomWeapon);
			}
			if (val2.m_randomSets != null)
			{
				ItemSet[] randomSets = val2.m_randomSets;
				foreach (ItemSet val3 in randomSets)
				{
					if (val3 != null && val3.m_items != null)
					{
						list.AddRange(val3.m_items);
					}
				}
			}
		}
		else if (src.StartsWith("item:") && (Object)(object)ObjectDB.instance != (Object)null)
		{
			string text = src.Substring(5).ToLowerInvariant();
			bool flag = text.StartsWith("*") && text.EndsWith("*");
			string value = text.Trim('*');
			foreach (GameObject item in ObjectDB.instance.m_items)
			{
				if ((Object)(object)item != (Object)null && (flag ? ((Object)item).name.ToLowerInvariant().Contains(value) : (((Object)item).name.ToLowerInvariant() == text)))
				{
					list.Add(item);
				}
			}
		}
		return list;
	}

	private static Shot Find(string src, int el)
	{
		if (src.StartsWith("projectile:"))
		{
			string text = src.Substring(11);
			GameObject val = (text.Contains("*") ? Wild(text) : Prefab(text));
			Shot shot = ((el != 1) ? ShotOf(1) : null);
			if ((Object)(object)val == (Object)null || val.GetComponent<IProjectile>() == null || shot == null)
			{
				return null;
			}
			Shot shot2 = new Shot();
			shot2.Item = shot.Item;
			shot2.Attack = shot.Attack;
			shot2.Prefab = val;
			shot2.AtTarget = false;
			shot2.From = ((Object)val).name;
			return shot2;
		}
		Shot result = null;
		float num = -1f;
		foreach (GameObject item in ItemsOf(src))
		{
			ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val2 == (Object)null)
			{
				continue;
			}
			SharedData shared = val2.m_itemData.m_shared;
			Attack[] array = (Attack[])(object)new Attack[2] { shared.m_attack, shared.m_secondaryAttack };
			foreach (Attack val3 in array)
			{
				if (val3 == null)
				{
					continue;
				}
				GameObject val4 = val3.m_attackProjectile;
				bool atTarget = false;
				if ((Object)(object)val4 == (Object)null || val4.GetComponent<IProjectile>() == null)
				{
					val4 = val3.m_spawnOnTrigger;
					atTarget = true;
					if ((Object)(object)val4 == (Object)null || val4.GetComponent<IProjectile>() == null)
					{
						continue;
					}
				}
				float num2 = ((DamageTypes)(ref shared.m_damages)).GetTotalDamage();
				string text2 = (((Object)item).name + " " + ((Object)val4).name).ToLowerInvariant();
				if (el == 5 && (text2.Contains("lightning") || text2.Contains("antler") || text2.Contains("thunder")))
				{
					num2 += 10000f;
				}
				if (el == 2 && text2.Contains("fire"))
				{
					num2 += 10000f;
				}
				if (el == 3 && text2.Contains("poison"))
				{
					num2 += 10000f;
				}
				if (num2 > num)
				{
					num = num2;
					Shot shot3 = new Shot();
					shot3.Item = val2.m_itemData;
					shot3.Attack = val3;
					shot3.Prefab = val4;
					shot3.AtTarget = atTarget;
					shot3.From = ((Object)item).name;
					result = shot3;
				}
			}
		}
		return result;
	}

	private static GameObject Wild(string pattern)
	{
		if ((Object)(object)ZNetScene.instance == (Object)null)
		{
			return null;
		}
		string text = pattern.Trim('*').ToLowerInvariant();
		List<string> list = new List<string>();
		GameObject val = null;
		foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
		{
			if ((Object)(object)prefab == (Object)null || prefab.GetComponent<IProjectile>() == null || (Object)(object)prefab.GetComponent<ItemDrop>() != (Object)null)
			{
				continue;
			}
			string text2 = ((Object)prefab).name.ToLowerInvariant();
			if (text2.Contains(text))
			{
				list.Add(((Object)prefab).name);
				if (!text2.Contains("bomb") && !text2.Contains("bile") && !text2.Contains("bottle") && !text2.Contains("flask") && !text2.Contains("potion") && !text2.Contains("mead") && ((Object)(object)val == (Object)null || (text2.Contains("projectile") && !((Object)val).name.ToLowerInvariant().Contains("projectile"))))
				{
					val = prefab;
				}
			}
		}
		Plugin.Debug("[drake] projectiles with '" + text + "': " + string.Join(", ", list.ToArray()) + " -> " + (((Object)(object)val != (Object)null) ? ((Object)val).name : "none"));
		return val;
	}

	private static GameObject Strike()
	{
		if (_strikeLooked)
		{
			return _strike;
		}
		if ((Object)(object)ZNetScene.instance == (Object)null)
		{
			return null;
		}
		_strikeLooked = true;
		List<string> list = new List<string>();
		GameObject val = null;
		int num = -1;
		foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				continue;
			}
			string text = ((Object)prefab).name.ToLowerInvariant();
			if ((!text.Contains("lightning") && !text.Contains("thunder")) || (Object)(object)prefab.GetComponent<ItemDrop>() != (Object)null || (Object)(object)prefab.GetComponent<Character>() != (Object)null)
			{
				continue;
			}
			list.Add(((Object)prefab).name);
			if (prefab.GetComponent<IProjectile>() != null)
			{
				int num2 = (text.Contains("aoe") ? 4 : 0) + (text.Contains("strike") ? 2 : 0) + ((text.StartsWith("fx_") || text.StartsWith("vfx_")) ? (-3) : 0);
				if (num2 > num)
				{
					num = num2;
					val = prefab;
				}
			}
		}
		_strike = val;
		Plugin.Debug("[drake] lightning prefabs: " + string.Join(", ", list.ToArray()) + " -> strike effect " + (((Object)(object)val != (Object)null) ? ((Object)val).name : "none"));
		return _strike;
	}

	internal static void Shoot(Character c, Player rider)
	{
		if (Time.time < _nextShot || (Object)(object)_pending != (Object)null || _burstLeft > 0)
		{
			return;
		}
		if (!Aiming)
		{
			Say("Hold the right mouse button to aim, then shoot with the left.");
			return;
		}
		if (!MayAttack(c))
		{
			Say("Too high to attack: fly lower.");
			return;
		}
		int el = ElementOf(c);
		if (ShotOf(el) == null)
		{
			Say("Your drake has no attack.");
			return;
		}
		if ((Object)(object)_queuedC == (Object)null && !c.IsFlying())
		{
			if (!TakeOffToAttack(c))
			{
				Say("Your drake is too tired to fly up and attack.");
				return;
			}
			_queuedC = c;
			_queuedRider = rider;
			_queuedAt = Time.time + 1f;
			return;
		}
		Humanoid val = (Humanoid)(object)((c is Humanoid) ? c : null);
		ItemData val2 = (((Object)(object)val != (Object)null) ? OwnMove(val) : null);
		_launched = false;
		_burstLeft = 0;
		_startedAt = Time.time;
		_nextShot = Time.time + 30f;
		if (val2 != null)
		{
			ZNetView val3 = Leash.View((Component)(object)c);
			if ((Object)(object)val3 != (Object)null && val3.IsValid() && !val3.IsOwner())
			{
				val3.ClaimOwnership();
			}
			if (val.GetCurrentWeapon() != val2)
			{
				val.EquipItem(val2, false);
			}
			_pending = c;
			_pendingRider = rider;
			if (((Character)val).StartAttack((Character)null, false))
			{
				Plugin.Debug("[drake] attack animation " + val2.m_shared.m_name + " (" + val2.m_shared.m_attack.m_attackAnimation + ")");
				return;
			}
			_pending = null;
		}
		Launch(c, rider);
		_nextShot = Time.time + Mathf.Max(0.2f, Plugin.DrakeAttackCooldown.Value);
	}

	private static ItemData OwnMove(Humanoid h)
	{
		ItemData val = null;
		foreach (ItemData allItem in h.GetInventory().GetAllItems())
		{
			if (allItem != null && allItem.IsWeapon() && allItem.m_shared.m_attack != null && !string.IsNullOrEmpty(allItem.m_shared.m_attack.m_attackAnimation))
			{
				if ((Object)(object)allItem.m_shared.m_attack.m_attackProjectile != (Object)null)
				{
					return allItem;
				}
				if (val == null)
				{
					val = allItem;
				}
			}
		}
		return val;
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(Attack), "ProjectileAttackTriggered")]
	private static bool AtTheMoment(Attack __instance)
	{
		if ((Object)(object)_pending == (Object)null || _launched)
		{
			return true;
		}
		Humanoid value = Traverse.Create((object)__instance).Field("m_character").GetValue<Humanoid>();
		if ((Object)(object)value != (Object)(object)_pending)
		{
			return true;
		}
		Launch((Character)(object)value, _pendingRider);
		return false;
	}

	internal static void Tick()
	{
		if ((Object)(object)_queuedC != (Object)null && Time.time >= _queuedAt)
		{
			Character queuedC = _queuedC;
			_queuedC = null;
			if ((Object)(object)queuedC != (Object)null && !queuedC.IsDead() && (Object)(object)Mount.RiddenCharacter() == (Object)(object)queuedC && queuedC.IsFlying())
			{
				_queuedC = queuedC;
				Shoot(queuedC, _queuedRider);
				_queuedC = null;
			}
		}
		if ((Object)(object)_pending == (Object)null && _burstLeft <= 0 && (Object)(object)_slowed == (Object)null)
		{
			return;
		}
		Character pending = _pending;
		Player pendingRider = _pendingRider;
		if ((Object)(object)pending == (Object)null || pending.IsDead() || (Object)(object)Mount.RiddenCharacter() != (Object)(object)pending)
		{
			Slow(null, on: false);
			_pending = null;
			_burstLeft = 0;
			return;
		}
		int el = ElementOf(pending);
		if (!_launched && Time.time - _startedAt > 1.4f)
		{
			Launch(pending, pendingRider);
		}
		if (_burstLeft > 0 && Time.time >= _burstNext)
		{
			_burstNext = Time.time + 0.16f;
			_burstLeft--;
			Spawn(pending, pendingRider, ShotOf(el), first: false);
		}
		Humanoid val = (Humanoid)(object)((pending is Humanoid) ? pending : null);
		bool flag = (Object)(object)val != (Object)null && ((Character)val).InAttack();
		if (_launched && _burstLeft <= 0 && (!flag || Time.time - _startedAt > 8f))
		{
			Slow(null, on: false);
			_pending = null;
			float num = (IsStream(el) ? (_burstEnd - 1.6f) : Time.time);
			_nextShot = Mathf.Max(Time.time, num + Mathf.Max(0.2f, Plugin.DrakeAttackCooldown.Value));
		}
	}

	private static void Slow(Character c, bool on)
	{
		if (!on)
		{
			if ((Object)(object)_slowed != (Object)null)
			{
				_slowed.speed = _slowedSpeed;
			}
			_slowed = null;
			return;
		}
		Animator val = (((Object)(object)c != (Object)null) ? ((Component)c).GetComponentInChildren<Animator>() : null);
		if (!((Object)(object)val == (Object)null))
		{
			_slowed = val;
			_slowedSpeed = val.speed;
			val.speed = _slowedSpeed * 0.5f;
		}
	}

	private static void NewAttack(int el)
	{
		_dealt.Clear();
		_attackUntil = Time.time + (IsStream(el) ? 1.6f : 0f) + 5f;
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(Character), "Damage")]
	[HarmonyPriority(200)]
	private static bool Budget(Character __instance, HitData hit)
	{
		if (hit == null || (Object)(object)__instance == (Object)null || Time.time > _attackUntil)
		{
			return true;
		}
		Character val = Mount.RiddenCharacter();
		if ((Object)(object)val == (Object)null || (Object)(object)hit.GetAttacker() != (Object)(object)val || !Is(val))
		{
			return true;
		}
		float totalDamage = hit.GetTotalDamage();
		if (totalDamage <= 0f)
		{
			return true;
		}
		_dealt.TryGetValue(__instance, out var value);
		float num = Plugin.DrakeAttackDamage.Value * 2f;
		if (ElementOf(val) == 2)
		{
			num = Mathf.Min(num, Plugin.DrakeFireMax.Value);
		}
		float num2 = num - value;
		if (num2 <= 0.01f)
		{
			return false;
		}
		if (totalDamage > num2)
		{
			((DamageTypes)(ref hit.m_damage)).Modify(num2 / totalDamage);
		}
		_dealt[__instance] = value + Mathf.Min(totalDamage, num2);
		return true;
	}

	private static void Launch(Character c, Player rider)
	{
		_launched = true;
		NewAttack(ElementOf(c));
		int el = ElementOf(c);
		Shot shot = ShotOf(el);
		if (shot != null)
		{
			Spawn(c, rider, shot, first: true);
			if (IsStream(el))
			{
				_burstLeft = Mathf.RoundToInt(10f);
				_burstNext = Time.time + 0.16f;
				_burstEnd = Time.time + 1.6f;
			}
		}
	}

	private static void Spawn(Character c, Player rider, Shot s, bool first)
	{
		//IL_0015: 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_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_0025: 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_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_003c: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_012c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Expected O, but got Unknown
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_0137: Unknown result type (might be due to invalid IL or missing references)
		//IL_0196: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_027e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0299: Unknown result type (might be due to invalid IL or missing references)
		//IL_029e: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bc: 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_02b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
		//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0352: Unknown result type (might be due to invalid IL or missing references)
		//IL_0347: Unknown result type (might be due to invalid IL or missing references)
		//IL_034b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0380: Unknown result type (might be due to invalid IL or missing references)
		//IL_0399: Unknown result type (might be due to invalid IL or missing references)
		if (s == null || (Object)(object)c == (Object)null)
		{
			return;
		}
		int num = ElementOf(c);
		Vector3 headPoint = c.GetHeadPoint();
		Vector3 val = AimPoint(c, rider);
		Vector3 val2 = val - headPoint;
		Vector3 normalized = ((Vector3)(ref val2)).normalized;
		Attack attack = s.Attack;
		Quaternion val3 = Quaternion.LookRotation(normalized);
		float num2 = Mathf.Max(1f, ((Component)c).transform.localScale.x);
		Vector3 val4 = headPoint + normalized * 1.2f * num2;
		DamageTypes damage = default(DamageTypes);
		float num3 = Plugin.DrakeAttackDamage.Value;
		if (IsStream(num))
		{
			num3 /= Mathf.Max(1f, 10f) / 2f;
		}
		else if (num == 1 || num == 4)
		{
			num3 *= 2f;
		}
		switch (num)
		{
		case 2:
			damage.m_fire = num3;
			break;
		case 3:
			damage.m_damage = num3 * 0.5f;
			damage.m_poison = num3 * 0.5f;
			break;
		case 4:
			damage.m_blunt = num3;
			break;
		case 5:
			damage.m_lightning = num3;
			break;
		default:
			damage.m_frost = num3;
			break;
		}
		HitData hd = new HitData();
		hd.m_damage = damage;
		hd.m_pushForce = s.Item.m_shared.m_attackForce;
		hd.m_toolTier = (short)s.Item.m_shared.m_toolTier;
		hd.m_dodgeable = true;
		hd.m_ranged = true;
		hd.m_blockable = true;
		if (first)
		{
			if (attack.m_startEffect != null)
			{
				attack.m_startEffect.Create(val4, val3, (Transform)null, 1f, -1, default(ZDOID));
			}
			if (attack.m_triggerEffect != null)
			{
				attack.m_triggerEffect.Create(val4, val3, (Transform)null, 1f, -1, default(ZDOID));
			}
		}
		int num4 = (s.AtTarget ? 1 : Mathf.Clamp(attack.m_projectiles, 1, 12));
		if (IsStream(num) || num == 1 || num == 4)
		{
			num4 = 1;
		}
		float num5 = Mathf.Max(20f, attack.m_projectileVel) * Mathf.Max(0.5f, Plugin.DrakeAttackSpeed.Value);
		float num6 = (IsStream(num) ? 4f : ((num4 > 1) ? Mathf.Min(6f, attack.m_projectileAccuracy) : 0f));
		if (num4 > 1)
		{
			DamageTypes_Scale(ref hd, 1f / (float)num4);
		}
		for (int i = 0; i < num4; i++)
		{
			Vector3 val5 = val3 * (Quaternion.Euler(Random.Range(0f - num6, num6), Random.Range(0f - num6, num6), 0f) * Vector3.forward);
			Vector3 val6 = (s.AtTarget ? (val + Vector3.up * 0.1f) : val4);
			GameObject val7 = Object.Instantiate<GameObject>(s.Prefab, val6, s.AtTarget ? Quaternion.identity : Quaternion.LookRotation(val5));
			IProjectile component = val7.GetComponent<IProjectile>();
			if (component == null)
			{
				Object.Destroy((Object)(object)val7);
				continue;
			}
			NoSpawns(val7);
			if (num == 4 && (Object)(object)val7.GetComponent<Projectile>() != (Object)null)
			{
				_rocks.Add(val7.GetComponent<Projectile>());
			}
			component.Setup(c, s.AtTarget ? Vector3.zero : (val5 * num5), attack.m_attackHitNoise, hd, s.Item, (ItemData)null);
			if (num == 1 && !s.AtTarget)
			{
				Transform transform = val7.transform;
				transform.localScale *= Mathf.Max(0.5f, Plugin.DrakeFrostSize.Value);
			}
		}
		if (num == 5 && first)
		{
			Strike(c, val, attack, s);
		}
		if (first)
		{
			Plugin.Debug("[drake] " + ElementName(num) + " shot from " + s.From + ": " + ((Object)s.Prefab).name + (s.AtTarget ? " at the target" : (" at " + num5.ToString("0") + " m/s")));
		}
	}

	[HarmonyPatch(typeof(Character), "ApplyDamage")]
	[HarmonyPrefix]
	private static void Landed(Character __instance, HitData hit, DamageModifier mod)
	{
		//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_006b: Unknown result type (might be due to invalid IL or missing references)
		if (hit != null && !((Object)(object)Mount.RiddenCharacter() == (Object)null) && !((Object)(object)hit.GetAttacker() != (Object)(object)Mount.RiddenCharacter()))
		{
			DamageTypes damage = hit.m_damage;
			Plugin.Debug(string.Concat("[drake] hit ", ((Object)__instance).name, " for ", hit.GetTotalDamage().ToString("0.0"), " (", mod, "; frost ", damage.m_frost.ToString("0"), " fire ", damage.m_fire.ToString("0"), " poison ", damage.m_poison.ToString("0"), " true ", damage.m_damage.ToString("0"), " blunt ", damage.m_blunt.ToString("0"), " lightning ", damage.m_lightning.ToString("0"), "), health ", __instance.GetHealth().ToString("0"), "/", __instance.GetMaxHealth().ToString("0")));
		}
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(Projectile), "OnHit")]
	private static void RockHit(Projectile __instance, Vector3 hitPoint)
	{
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		if (_rocks.Remove(__instance))
		{
			_rocks.RemoveWhere((Projectile r) => (Object)(object)r == (Object)null);
			Transform val = (((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform : null);
			float num = (((Object)(object)val != (Object)null) ? Vector3.Distance(val.position, hitPoint) : 0f);
			Effects.Shake(Mathf.Lerp(0.5f, 0.15f, Mathf.InverseLerp(5f, 60f, num)));
		}
	}

	private static void NoSpawns(GameObject go)
	{
		Projectile component = go.GetComponent<Projectile>();
		if ((Object)(object)component == (Object)null)
		{
			return;
		}
		if ((Object)(object)component.m_spawnOnHit != (Object)null && ((Object)(object)component.m_spawnOnHit.GetComponent<Character>() != (Object)null || (Object)(object)component.m_spawnOnHit.GetComponent<ItemDrop>() != (Object)null))
		{
			component.m_spawnOnHit = null;
		}
		if (component.m_randomSpawnOnHit != null)
		{
			component.m_randomSpawnOnHit.RemoveAll((GameObject g) => (Object)(object)g == (Object)null || (Object)(object)g.GetComponent<Character>() != (Object)null || (Object)(object)g.GetComponent<ItemDrop>() != (Object)null);
		}
		if ((Object)(object)component.m_spawnOnHit != (Object)null && (Object)(object)component.m_spawnOnHit.GetComponent<Aoe>() != (Object)null)
		{
			component.m_spawnOnHit = null;
		}
		if (component.m_randomSpawnOnHit != null)
		{
			component.m_randomSpawnOnHit.RemoveAll((GameObject g) => (Object)(object)g.GetComponent<Aoe>() != (Object)null);
		}
		component.m_onlySpawnedProjectilesDealDamage = false;
		component.m_respawnItemOnHit = false;
		component.m_spawnItem = null;
	}

	private static void DamageTypes_Scale(ref HitData hd, float k)
	{
		((DamageTypes)(ref hd.m_damage)).Modify(k);
	}

	private static Vector3 AimPoint(Character c, Player rider)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: 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_00cb: 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_00d5: 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_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: 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_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_0146: Unknown result type (might be due to invalid IL or missing references)
		Transform val = (((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform : null);
		if ((Object)(object)val == (Object)null)
		{
			return c.GetHeadPoint() + ((Component)c).transform.forward * 50f;
		}
		RaycastHit[] array = Physics.RaycastAll(val.position, val.forward, 250f, LayerMask.GetMask(new string[8] { "Default", "static_solid", "terrain", "piece", "character", "character_net", "character_ghost", "Water" }), (QueryTriggerInteraction)1);
		float num = float.MaxValue;
		Vector3 result = val.position + val.forward * 250f;
		RaycastHit[] array2 = array;
		for (int i = 0; i < array2.Length; i++)
		{
			RaycastHit val2 = array2[i];
			if (!((Object)(object)((RaycastHit)(ref val2)).collider == (Object)null))
			{
				Character componentInParent = ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<Character>();
				if (!((Object)(object)componentInParent == (Object)(object)c) && !((Object)(object)componentInParent == (Object)(object)rider) && !(((RaycastHit)(ref val2)).distance < 3f) && ((RaycastHit)(ref val2)).distance < num)
				{
					num = ((RaycastHit)(ref val2)).distance;
					result = ((RaycastHit)(ref val2)).point;
				}
			}
		}
		return result;
	}

	private static GameObject Prefab(string name)
	{
		if (!((Object)(object)ZNetScene.instance != (Object)null))
		{
			return null;
		}
		return ZNetScene.instance.GetPrefab(name);
	}

	private static bool Lights(GameObject g)
	{
		if ((Object)(object)g == (Object)null)
		{
			return false;
		}
		if ((Object)(object)g.GetComponentInChildren<Light>(true) != (Object)null)
		{
			return true;
		}
		MonoBehaviour[] componentsInChildren = g.GetComponentsInChildren<MonoBehaviour>(true);
		foreach (MonoBehaviour val in componentsInChildren)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			FieldInfo[] fields = ((object)val).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public);
			foreach (FieldInfo fieldInfo in fields)
			{
				object? value = fieldInfo.GetValue(val);
				EffectList val2 = (EffectList)((value is EffectList) ? value : null);
				if (val2 == null || val2.m_effectPrefabs == null)
				{
					continue;
				}
				EffectData[] effectPrefabs = val2.m_effectPrefabs;
				foreach (EffectData val3 in effectPrefabs)
				{
					if (val3 != null && (Object)(object)val3.m_prefab != (Object)null && (Object)(object)val3.m_prefab.GetComponentInChildren<Light>(true) != (Object)null)
					{
						return true;
					}
				}
			}
		}
		return false;
	}

	private static void Strike(Character c, Vector3 target, Attack a, Shot s)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: 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_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Expected O, but got Unknown
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_0122: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		Vector3 val = target + Vector3.up * 0.1f;
		GameObject val2 = Prefab("lightningAOE") ?? Strike();
		GameObject val3 = Prefab("fx_Lightning");
		bool flag = false;
		if ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)s.Prefab)
		{
			GameObject val4 = Object.Instantiate<GameObject>(val2, val, Quaternion.identity);
			IProjectile component = val4.GetComponent<IProjectile>();
			HitData val5 = new HitData();
			val5.m_damage = default(DamageTypes);
			val5.m_damage.m_lightning = Plugin.DrakeAttackDamage.Value;
			val5.m_ranged = true;
			Aoe component2 = val4.GetComponent<Aoe>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.m_useAttackSettings = true;
				component2.m_hitInterval = 0f;
				component2.m_chainStartChance = 0f;
				component2.m_damagePerLevel = default(DamageTypes);
			}
			val5.m_dodgeable = true;
			val5.m_blockable = true;
			if (component != null)
			{
				component.Setup(c, Vector3.zero, a.m_attackHitNoise, val5, s.Item, (ItemData)null);
			}
			flag = Lights(val2);
		}
		if (!flag && (Object)(object)val3 != (Object)null)
		{
			Object.Instantiate<GameObject>(val3, val, Quaternion.identity);
		}
		Plugin.Debug("[drake] lightning at the target: " + (((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "no area") + (flag ? " (it has its own light)" : (((Object)(object)val3 != (Object)null) ? (" + " + ((Object)val3).name) : "")));
	}

	internal static void KeepSafe(float seconds)
	{
		_safeUntil = Mathf.Max(_safeUntil, Time.time + seconds);
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(Character), "Damage")]
	private static bool NoFall(Character __instance, HitData hit)
	{
		//IL_0036: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		if (hit == null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
		{
			return true;
		}
		if (Time.time - OffAt < 6f)
		{
			Plugin.Debug(string.Concat("[drake] you were hit just after getting off: ", hit.m_hitType, ", ", hit.GetTotalDamage().ToString("0"), " damage, from ", ((Object)(object)hit.GetAttacker() != (Object)null) ? ((Object)hit.GetAttacker()).name : "nothing"));
		}
		if (Time.time > _safeUntil)
		{
			return true;
		}
		Plugin.Debug(string.Concat("[drake] a hit on the rider was cancelled while climbing on (", hit.m_hitType, ")"));
		return false;
	}

	internal static string ElementName(int el)
	{
		return el switch
		{
			2 => "Fire", 
			3 => "Poison", 
			4 => "Earth", 
			5 => "Lightning", 
			_ => "Frost", 
		};
	}

	internal static int ElementOf(Character c)
	{
		ZNetView val = Leash.View((Component)(object)c);
		int num = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO().GetInt(ElementKey, 0) : 0);
		if (num < 1 || num > 5)
		{
			return 1;
		}
		return num;
	}

	internal static void MakeBaby(Character baby, ZNetView nv, int el, Vector3 home)
	{
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		ZDO zDO = nv.GetZDO();
		zDO.Set(ElementKey, el, false);
		zDO.Set(BornKey, Breed.Now());
		if (Random.value < Plugin.DrakeGlowChance.Value)
		{
			zDO.Set(GlowKey, 1, false);
		}
		zDO.Set(Halter.Key, 1, false);
		baby.SetTamed(true);
		Home.Set(baby, home);
		KeepSize(baby);
		baby.Land();
	}

	internal static float Grown(Character c)
	{
		ZNetView val = Leash.View((Component)(object)c);
		if ((Object)(object)val == (Object)null || !val.IsValid())
		{
			return 1f;
		}
		float num = val.GetZDO().GetFloat(BornKey, 0f);
		if (num <= 0f)
		{
			return 1f;
		}
		return Mathf.Clamp01((Breed.Now() - num) / Mathf.Max(60f, Plugin.DrakeGrowMinutes.Value * 60f));
	}

	internal static int MinutesToGrow(Character c)
	{
		return Mathf.CeilToInt((1f - Grown(c)) * Plugin.DrakeGrowMinutes.Value);
	}

	internal static void Attach(Character c)
	{
		if (Is(c))
		{
			if ((Object)(object)((Component)c).GetComponent<DrakeLook>() == (Object)null)
			{
				((Component)c).gameObject.AddComponent<DrakeLook>();
			}
			if ((Object)(object)((Component)c).GetComponent<DrakeGround>() == (Object)null)
			{
				((Component)c).gameObject.AddComponent<DrakeGround>();
			}
			if ((Object)(object)((Component)c).GetComponent<DrakeWalk>() == (Object)null)
			{
				((Component)c).gameObject.AddComponent<DrakeWalk>();
			}
		}
	}

	internal static void ColorsChanged()
	{
		Palettes.Clear();
		PaletteVersion++;
	}

	internal static Palette PaletteOf(int el)
	{
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0143: Unknown result type (might be due to invalid IL or missing references)
		if (el < 1 || el > 5)
		{
			el = 1;
		}
		if (Palettes.TryGetValue(el, out var value))
		{
			return value;
		}
		value = new Palette();
		string text = ((Plugin.DrakeColors != null && Plugin.DrakeColors[el - 1] != null) ? Plugin.DrakeColors[el - 1].Value : "");
		string[] array = (text ?? "").Split(',');
		Color value2 = default(Color);
		foreach (string text2 in array)
		{
			string[] array2 = text2.Split(':');
			if (array2.Length != 2)
			{
				continue;
			}
			string text3 = array2[0].Trim().ToLowerInvariant();
			string text4 = array2[1].Trim();
			Color? val = (ColorUtility.TryParseHtmlString(text4, ref value2) ? new Color?(value2) : ((Color?)null));
			switch (text3)
			{
			case "scales":
				value.Scales = val;
				break;
			case "wings":
				value.Wings = val;
				break;
			case "horns":
				value.Horns = val;
				break;
			case "eyes":
				value.Eyes = val;
				break;
			case "glow":
				if (val.HasValue)
				{
					value.Glow = val.Value;
				}
				break;
			}
		}
		Palettes[el] = value;
		return value;
	}
}
[HarmonyPatch]
internal static class DrakeCommand
{
	[HarmonyPostfix]
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	private static void Add()
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Expected O, but got Unknown
		//IL_0020: Unknown result type (might be due to invalid IL or missing references)
		new ConsoleCommand("bk_drake", "[frost|fire|poison|earth|lightning] [glow] - a tamed grown drake (Beastkeeper)", new ConsoleEvent(Run), true, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
	}

	private static void Run(ConsoleEventArgs args)
	{
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//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_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0191: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || (Object)(object)ZNetScene.instance == (Object)null)
		{
			return;
		}
		int num;
		switch ((args.Length > 1) ? args[1].ToLowerInvariant() : "frost")
		{
		default:
			num = 1;
			break;
		case "lightning":
			num = 5;
			break;
		case "earth":
		case "stone":
			num = 4;
			break;
		case "poison":
			num = 3;
			break;
		case "fire":
			num = 2;
			break;
		}
		int num2 = num;
		GameObject prefab = ZNetScene.instance.GetPrefab("Hatchling");
		if ((Object)(object)prefab == (Object)null)
		{
			args.Context.AddString("No drake prefab.");
			return;
		}
		Vector3 val = ((Component)localPlayer).transform.position + ((Component)localPlayer).transform.forward * 4f + Vector3.up;
		GameObject val2 = Object.Instantiate<GameObject>(prefab, val, Quaternion.LookRotation(-((Component)localPlayer).transform.forward));
		Character component = val2.GetComponent<Character>();
		ZNetView val3 = Leash.View((Component)(object)component);
		if (!((Object)(object)component == (Object)null) && !((Object)(object)val3 == (Object)null) && val3.IsValid())
		{
			ZDO zDO = val3.GetZDO();
			zDO.Set(Drake.ElementKey, num2, false);
			if (args.Length > 2 && args[2].ToLowerInvariant() == "glow")
			{
				zDO.Set(Drake.GlowKey, 1, false);
			}
			zDO.Set(Halter.Key, 1, false);
			component.SetTamed(true);
			Home.Set(component, val);
			Drake.KeepSize(component);
			args.Context.AddString("A grown " + Drake.ElementName(num2) + " drake.");
		}
	}
}
[HarmonyPatch]
internal static class DrakeEgg
{
	internal class EggWarmer : MonoBehaviour
	{
		private ItemDrop _item;

		private ZNetView _nv;

		private float _next;

		private void Awake()
		{
			_item = ((Component)this).GetComponent<ItemDrop>();
			_nv = ((Component)this).GetComponent<ZNetView>();
			_next = Time.time + Random.Range(1f, 5f);
		}

		private void Update()
		{
			if (Time.time < _next)
			{
				return;
			}
			_next = Time.time + 5f;
			if (!On() || (Object)(object)_item == (Object)null || (Object)(object)_nv == (Object)null || !_nv.IsValid() || !_nv.IsOwner())
			{
				return;
			}
			ZDO zDO = _nv.GetZDO();
			int num = zDO.GetInt(Drake.ElementKey, 0);
			if (num != 0 && _item.m_itemData.m_stack <= 1 && ModerDead() && Warm(_item))
			{
				float num2 = zDO.GetFloat(WarmKey, 0f) + 5f;
				zDO.Set(WarmKey, num2);
				if (num2 >= HatchSeconds)
				{
					Hatch(num);
				}
			}
		}

		private void Hatch(int el)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: 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_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(Drake.BabyPrefab) : null);
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)("No " + Drake.BabyPrefab + " prefab: the egg can't hatch."));
				return;
			}
			Vector3 val2 = ((Component)this).transform.position + Vector3.up * 0.3f;
			GameObject val3 = Object.Instantiate<GameObject>(val, val2, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f));
			Character component = val3.GetComponent<Character>();
			ZNetView component2 = val3.GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && !((Object)(object)component2 == (Object)null) && component2.IsValid())
			{
				Drake.MakeBaby(component, component2, el, val2);
				GameObject prefab = ZNetScene.instance.GetPrefab("Boar");
				Procreation val4 = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Procreation>() : null);
				if ((Object)(object)val4 != (Object)null && val4.m_birthEffects != null)
				{
					val4.m_birthEffects.Create(val2, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID));
				}
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null && Vector3.Distance(((Component)localPlayer).transform.position, val2) < 30f)
				{
					((Character)localPlayer).Message((MessageType)2, "A " + Drake.ElementName(el).ToLowerInvariant() + " drake hatched!" + ((component2.GetZDO().GetInt(Drake.GlowKey, 0) == 1) ? " Its eyes and horns glow!" : ""), 0, (Sprite)null, false);
				}
				Plugin.Debug("[egg] hatched a " + Drake.ElementName(el) + " drake at " + val2);
				_nv.Destroy();
			}
		}
	}

	internal const string EggPrefab = "DragonEgg";

	private const string ModerKey = "defeated_dragon";

	private static readonly int WarmKey = StringExtensionMethods.GetStableHashCode("Beastkeeper_eggWarm");

	private static float HatchSeconds => Mathf.Max(10f, Plugin.DrakeHatchMinutes.Value * 60f);

	internal static bool IsEgg(GameObject go)
	{
		if ((Object)(object)go != (Object)null)
		{
			return Utils.GetPrefabName(go) == "DragonEgg";
		}
		return false;
	}

	private static bool ModerDead()
	{
		if ((Object)(object)ZoneSystem.instance != (Object)null)
		{
			return ZoneSystem.instance.GetGlobalKey("defeated_dragon");
		}
		return false;
	}

	private static bool On()
	{
		if (Plugin.Enabled.Value && Plugin.DrakeMounts != null)
		{
			return (Plugin.DrakeMounts.Value ?? "").Trim().Length > 0;
		}
		return false;
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(Humanoid), "Pickup")]
	private static void BeforePickup(Humanoid __instance, GameObject go, out Vector3 __state)
	{
		//IL_0016: 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_001b: Unknown result type (might be due to invalid IL or missing references)
		__state = (IsEgg(go) ? go.transform.position : Vector3.zero);
	}

	[HarmonyPostfix]
	[HarmonyPatch(typeof(Humanoid), "Pickup")]
	private static void AfterPickup(Humanoid __instance, bool __result, Vector3 __state)
	{
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_0004: 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_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Unknown result type (might be due to invalid IL or missing references)
		if (!__result || __state == Vector3.zero || !On() || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
		{
			return;
		}
		int num = 0;
		foreach (Character allCharacter in Character.GetAllCharacters())
		{
			if (!((Object)(object)allCharacter == (Object)null) && !allCharacter.IsDead() && !allCharacter.IsTamed() && Drake.Is(allCharacter) && !(Vector3.Distance(((Component)allCharacter).transform.position, __state) > Plugin.DrakeEggAlertRange.Value))
			{
				MonsterAI component = ((Component)allCharacter).GetComponent<MonsterAI>();
				if (!((Object)(object)component == (Object)null))
				{
					Traverse.Create((object)component).Field("m_targetCreature").SetValue((object)__instance);
					((BaseAI)component).Alert();
					num++;
				}
			}
		}
		if (num > 0)
		{
			((Character)__instance).Message((MessageType)2, (num == 1) ? "A drake saw you take the egg!" : (num + " drakes saw you take the egg!"), 0, (Sprite)null, false);
		}
		Plugin.Debug(string.Concat("[egg] taken from ", __state, ": ", num, " drakes come for it"));
	}

	internal static int ElementOf(ItemData item)
	{
		if (item == null || (Object)(object)item.m_dropPrefab == (Object)null)
		{
			return 0;
		}
		switch (((Object)item.m_dropPrefab).name)
		{
		case "FreezeGland":
		case "Crystal":
			return 1;
		case "SurtlingCore":
			return 2;
		case "Ooze":
			return 3;
		case "Obsidian":
			return 4;
		case "Thunderstone":
			return 5;
		default:
			return 0;
		}
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(ItemDrop), "UseItem")]
	private static bool GiveItem(ItemDrop __instance, Humanoid user, ItemData item, ref bool __result)
	{
		if (!On() || !IsEgg(((Component)__instance).gameObject))
		{
			return true;
		}
		Player val = (Player)(object)((user is Player) ? user : null);
		ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
		if ((Object)(object)val == (Object)null || (Object)(object)component == (Object)null || !component.IsValid())
		{
			return true;
		}
		__result = true;
		if (!ModerDead())
		{
			((Character)val).Message((MessageType)2, "The egg is cold and still. Its mother still lives.", 0, (Sprite)null, false);
			return false;
		}
		if (__instance.m_itemData.m_stack > 1)
		{
			((Character)val).Message((MessageType)2, "Lay the eggs down one by one.", 0, (Sprite)null, false);
			return false;
		}
		if (component.GetZDO().GetInt(Drake.ElementKey, 0) != 0)
		{
			((Character)val).Message((MessageType)2, "This egg is already awake.", 0, (Sprite)null, false);
			return false;
		}
		int num = ElementOf(item);
		if (num == 0)
		{
			((Character)val).Message((MessageType)2, "The egg doesn't take that. " + Choices(), 0, (Sprite)null, false);
			return false;
		}
		if (!component.IsOwner())
		{
			component.ClaimOwnership();
		}
		component.GetZDO().Set(Drake.ElementKey, num, false);
		component.GetZDO().Set(WarmKey, 0f);
		((Humanoid)val).GetInventory().RemoveItem(item, 1);
		((Character)val).Message((MessageType)2, "The egg stirs: a " + Drake.ElementName(num).ToLowerInvariant() + " drake grows inside." + (Plugin.DrakeEggNeedsFire.Value ? " Keep it warm by a fire." : ""), 0, (Sprite)null, false);
		Plugin.Debug("[egg] woken with " + ((Object)item.m_dropPrefab).name + ": element " + num);
		return false;
	}

	private static string Choices()
	{
		return "Freeze Gland or Crystal (frost), Surtling Core (fire), Ooze (poison), Obsidian (earth), Thunderstone (lightning).";
	}

	[HarmonyPatch(typeof(Fireplace), "UseItem")]
	[HarmonyPrefix]
	private static bool LayByFire(Fireplace __instance, Humanoid user, ItemData item, ref bool __result)
	{
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Unknown result type (might be due to invalid IL or missing references)
		//IL_005d: Unknown result type (might be due to invalid IL or missing references)
		//IL_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)
		//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_00a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d2: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: 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_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: Unknown result type (might be due to invalid IL or missing references)
		//IL_0174: Unknown result type (might be due to invalid IL or missing references)
		//IL_0175: Unknown result type (might be due to invalid IL or missing references)
		//IL_017a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0155: Unknown result type (might be due to invalid IL