Decompiled source of Vampirizm v0.1.0

plugins/Vampirizm.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using SoftReferenceableAssets;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using Valheim.SettingsGui;
using Vampirizm.Abilities;
using Vampirizm.Combat;
using Vampirizm.Commands;
using Vampirizm.Configuration;
using Vampirizm.Controls;
using Vampirizm.Conversion;
using Vampirizm.Core;
using Vampirizm.Effects;
using Vampirizm.Feeding;
using Vampirizm.Items;
using Vampirizm.Localization;
using Vampirizm.Networking;
using Vampirizm.Persistence;
using Vampirizm.Skills;
using Vampirizm.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("Vampirizm")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a2b72bdbd3ca0d32403f81bd847cd3f4c7171140")]
[assembly: AssemblyProduct("Vampirizm")]
[assembly: AssemblyTitle("Vampirizm")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
}
namespace Vampirizm
{
	[BepInPlugin("com.igentuman.vampirizm", "Vampirizm", "0.1.0")]
	[BepInDependency("com.jotunn.jotunn", "2.29.2")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.igentuman.vampirizm";

		public const string PluginName = "Vampirizm";

		public const string PluginVersion = "0.1.0";

		private Harmony _harmony;

		internal static Plugin Instance { get; private set; }

		internal VampireConfig Settings { get; private set; }

		private void Awake()
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			Instance = this;
			Settings = new VampireConfig(((BaseUnityPlugin)this).Config);
			BloodItemRegistry.Initialize(Settings.BloodItems, Settings.AllowMeads);
			SilverRegistry.Initialize(Settings.SilverItems, Settings.SilverContactItems);
			DonorRegistry.Initialize(Settings.Donors, Settings.NeverDonors, Settings.NoHoldDonors);
			FriendlyRegistry.Initialize(Settings.FriendlyCreatures);
			VampireLocalization.Register();
			VampirismSkill.Register();
			VampireRune.Register();
			VampireCommand.Register();
			VampireInput.Register(((BaseUnityPlugin)this).Config);
			_harmony = new Harmony("com.igentuman.vampirizm");
			foreach (Type item in from type in typeof(Plugin).Assembly.GetTypes()
				where type.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0
				select type)
			{
				try
				{
					_harmony.CreateClassProcessor(item).Patch();
				}
				catch (Exception arg)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to install Harmony patches from {item.FullName}: {arg}");
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Vampirizm 0.1.0 loaded; Valheim " + Version.GetVersionString(false)));
		}

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

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

		internal static void SaveControlSettings()
		{
			try
			{
				Plugin instance = Instance;
				if (instance != null)
				{
					((BaseUnityPlugin)instance).Config.Save();
				}
			}
			catch (Exception arg)
			{
				Warn($"Could not save ability controls: {arg}");
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			VampireController[] array = Object.FindObjectsByType<VampireController>((FindObjectsSortMode)0);
			for (int i = 0; i < array.Length; i++)
			{
				array[i].Invisibility?.End(effects: false);
			}
			Instance = null;
		}
	}
}
namespace Vampirizm.UI
{
	internal sealed class BloodHud : MonoBehaviour
	{
		private const float Gap = 6f;

		private const float PowerGap = 14f;

		private const float BottomNudge = -18f;

		private const float IconDrop = 0.45f;

		private const float Inset = 2f;

		private const float IconScale = 0.8f;

		private const int IconResolution = 64;

		private const float HungryFraction = 0.2f;

		private static readonly Color FillColor = new Color(0.62f, 0.04f, 0.06f, 0.95f);

		private static readonly Color HungryColor = new Color(1f, 0.15f, 0.1f, 1f);

		private static readonly Vector3[] Corners = (Vector3[])(object)new Vector3[4];

		private static Sprite _dropSprite;

		private Hud _hud;

		private RectTransform _root;

		private RectTransform _fill;

		private Image _fillImage;

		private TextMeshProUGUI _text;

		private RectTransform _icon;

		private int _shownBlood = -1;

		private void Awake()
		{
			_hud = ((Component)this).GetComponent<Hud>();
			Build();
		}

		private void Build()
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: 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_01a4: 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_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = (RectTransform)(((Object)(object)_hud.m_healthPanel != (Object)null) ? ((object)_hud.m_healthPanel) : ((object)(((Object)(object)_hud.m_healthBarRoot != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null)));
			if (!((Object)(object)val == (Object)null))
			{
				_root = CreateRect("VampirizmBloodBar", (Transform)(object)val);
				RectTransform root = _root;
				RectTransform root2 = _root;
				Vector2 val2 = default(Vector2);
				((Vector2)(ref val2))..ctor(0.5f, 0.5f);
				root2.anchorMax = val2;
				root.anchorMin = val2;
				_root.pivot = new Vector2(0f, 0f);
				Image obj = ((Component)_root).gameObject.AddComponent<Image>();
				((Graphic)obj).color = new Color(0f, 0f, 0f, 0.6f);
				((Graphic)obj).raycastTarget = false;
				_fill = CreateRect("Fill", (Transform)(object)_root);
				_fill.anchorMin = Vector2.zero;
				_fill.anchorMax = Vector2.one;
				_fill.offsetMin = new Vector2(2f, 2f);
				_fill.offsetMax = new Vector2(-2f, -2f);
				_fillImage = ((Component)_fill).gameObject.AddComponent<Image>();
				((Graphic)_fillImage).color = FillColor;
				((Graphic)_fillImage).raycastTarget = false;
				RectTransform val3 = CreateRect("Value", (Transform)(object)_root);
				val3.anchorMin = Vector2.zero;
				val3.anchorMax = Vector2.one;
				val2 = (val3.offsetMin = (val3.offsetMax = Vector2.zero));
				_text = ((Component)val3).gameObject.AddComponent<TextMeshProUGUI>();
				((TMP_Text)_text).alignment = (TextAlignmentOptions)514;
				((Graphic)_text).raycastTarget = false;
				_icon = CreateRect("Drop", (Transform)(object)_root);
				RectTransform icon = _icon;
				RectTransform icon2 = _icon;
				((Vector2)(ref val2))..ctor(0.5f, 0f);
				icon2.anchorMax = val2;
				icon.anchorMin = val2;
				_icon.pivot = new Vector2(0.5f, 0.5f);
				Image obj2 = ((Component)_icon).gameObject.AddComponent<Image>();
				obj2.sprite = DropSprite();
				obj2.preserveAspect = true;
				((Graphic)obj2).raycastTarget = false;
				((Component)_root).gameObject.SetActive(false);
			}
		}

		private static RectTransform CreateRect(string name, Transform parent)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) })
			{
				layer = ((Component)parent).gameObject.layer
			}.transform;
			((Transform)val).SetParent(parent, false);
			return val;
		}

		private void LateUpdate()
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Expected O, but got Unknown
			//IL_009d: 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_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_0106: 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_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: 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_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: 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_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: 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_0379: Unknown result type (might be due to invalid IL or missing references)
			//IL_039a: Unknown result type (might be due to invalid IL or missing references)
			//IL_036d: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_root == (Object)null)
			{
				Build();
			}
			if ((Object)(object)_root == (Object)null)
			{
				return;
			}
			VampireController local = VampireController.Local;
			bool flag = (Object)(object)local != (Object)null && local.IsActiveVampire && (Object)(object)_hud.m_healthBarRoot != (Object)null;
			if (((Component)_root).gameObject.activeSelf != flag)
			{
				((Component)_root).gameObject.SetActive(flag);
			}
			if (!flag)
			{
				return;
			}
			RectTransform val = (RectTransform)((Transform)_root).parent;
			Bounds(_hud.m_healthBarRoot, (Transform)(object)val, out var min, out var max);
			float num = max.x + 6f;
			if ((Object)(object)_hud.m_gpRoot != (Object)null)
			{
				Bounds(_hud.m_gpRoot, (Transform)(object)val, out var _, out var max2);
				num = Mathf.Max(num, max2.x + 14f);
			}
			VampireConfig settings = Plugin.Instance.Settings;
			Vector2 val2 = max - min;
			_root.sizeDelta = new Vector2(val2.x + 1f, val2.y);
			RectTransform root = _root;
			Vector2 val3 = new Vector2(num + settings.HudOffsetX.Value, min.y + -18f + settings.HudOffsetY.Value);
			Rect rect = val.rect;
			root.anchoredPosition = val3 - ((Rect)(ref rect)).center;
			_icon.sizeDelta = new Vector2(val2.x * 0.8f, val2.x * 0.8f);
			_icon.anchoredPosition = new Vector2(0f, (0f - val2.x) * 0.45f);
			if ((Object)(object)_hud.m_healthText != (Object)null)
			{
				if ((Object)(object)((TMP_Text)_text).font != (Object)(object)_hud.m_healthText.font)
				{
					((TMP_Text)_text).font = _hud.m_healthText.font;
				}
				if ((Object)(object)((TMP_Text)_text).fontSharedMaterial != (Object)(object)_hud.m_healthText.fontSharedMaterial)
				{
					((TMP_Text)_text).fontSharedMaterial = _hud.m_healthText.fontSharedMaterial;
				}
				if (((TMP_Text)_text).fontSize != _hud.m_healthText.fontSize)
				{
					((TMP_Text)_text).fontSize = _hud.m_healthText.fontSize;
				}
				if (((TMP_Text)_text).fontStyle != _hud.m_healthText.fontStyle)
				{
					((TMP_Text)_text).fontStyle = _hud.m_healthText.fontStyle;
				}
				if (((Graphic)_text).color != ((Graphic)_hud.m_healthText).color)
				{
					((Graphic)_text).color = ((Graphic)_hud.m_healthText).color;
				}
			}
			float blood = local.State.Blood;
			float capacity = local.Capacity;
			float num2 = ((capacity > 0f) ? Mathf.Clamp01(blood / capacity) : 0f);
			_fill.anchorMax = new Vector2(1f, num2);
			((Behaviour)_fillImage).enabled = num2 * val2.y > 4f;
			((Graphic)_fillImage).color = ((num2 < 0.2f) ? Color.Lerp(FillColor, HungryColor, 0.5f + Mathf.Sin(Time.time * 6f) * 0.5f) : FillColor);
			int num3 = Mathf.CeilToInt(blood);
			if (num3 != _shownBlood)
			{
				_shownBlood = num3;
				((TMP_Text)_text).text = num3.ToString();
			}
		}

		private static void Bounds(RectTransform rect, Transform space, out Vector2 min, out Vector2 max)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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_0058: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			rect.GetWorldCorners(Corners);
			min = (max = Vector2.op_Implicit(space.InverseTransformPoint(Corners[0])));
			for (int i = 1; i < Corners.Length; i++)
			{
				Vector2 val = Vector2.op_Implicit(space.InverseTransformPoint(Corners[i]));
				min = Vector2.Min(min, val);
				max = Vector2.Max(max, val);
			}
		}

		private static Sprite DropSprite()
		{
			//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_007e: 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_008e: Expected O, but got Unknown
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_dropSprite != (Object)null)
			{
				return _dropSprite;
			}
			float num = 0.59999996f;
			float num2 = 0.36f + 0.09f / num;
			float num3 = 0.3f / Mathf.Sqrt(num * num - 0.09f);
			Color val = default(Color);
			((Color)(ref val))..ctor(0.95f, 0.25f, 0.25f);
			Color val2 = default(Color);
			((Color)(ref val2))..ctor(0.45f, 0.01f, 0.03f);
			Texture2D val3 = new Texture2D(64, 64, (TextureFormat)4, false)
			{
				name = "vampirizm_blood_drop",
				wrapMode = (TextureWrapMode)1,
				filterMode = (FilterMode)1
			};
			Color[] array = (Color[])(object)new Color[4096];
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					int num4 = 0;
					for (int k = 0; k < 4; k++)
					{
						for (int l = 0; l < 4; l++)
						{
							float num5 = ((float)j + ((float)l + 0.5f) / 4f) / 64f - 0.5f;
							float num6 = ((float)i + ((float)k + 0.5f) / 4f) / 64f;
							bool num7 = num5 * num5 + (num6 - 0.36f) * (num6 - 0.36f) <= 0.09f;
							bool flag = num6 >= num2 && num6 <= 0.96f && Mathf.Abs(num5) <= (0.96f - num6) * num3;
							if (num7 || flag)
							{
								num4++;
							}
						}
					}
					float num8 = ((float)j + 0.5f) / 64f - 0.5f;
					float num9 = ((float)i + 0.5f) / 64f;
					float num10 = Mathf.Clamp01(0.55f - num8 * 0.9f + (num9 - 0.36f) * 0.6f);
					Color val4 = Color.Lerp(val2, val, num10);
					Vector2 val5 = new Vector2(num8 + 0.11f, num9 - 0.42f);
					float magnitude = ((Vector2)(ref val5)).magnitude;
					val4 = Color.Lerp(val4, Color.white, Mathf.Clamp01((0.07f - magnitude) / 0.03f) * 0.8f);
					val4.a = (float)num4 / 16f;
					array[i * 64 + j] = val4;
				}
			}
			val3.SetPixels(array);
			val3.Apply();
			_dropSprite = Sprite.Create(val3, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f));
			((Object)_dropSprite).name = ((Object)val3).name;
			return _dropSprite;
		}
	}
}
namespace Vampirizm.Skills
{
	internal static class VampirismSkill
	{
		internal const string Identifier = "com.igentuman.vampirizm.skill";

		internal static SkillType Type { get; private set; }

		internal static void Register()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			Type = SkillManager.Instance.AddSkill(new SkillConfig
			{
				Identifier = "com.igentuman.vampirizm.skill",
				Name = "$vampirizm_skill",
				Description = "$vampirizm_skill_description",
				IncreaseStep = 1f
			});
		}

		internal static float Level(Player player)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return ((Character)player).GetSkills().GetSkillLevel(Type);
		}

		internal static void SetLevel(Player player, float level)
		{
			//IL_0028: 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)
			Level(player);
			foreach (Skill skill in ((Character)player).GetSkills().GetSkillList())
			{
				if (skill.m_info.m_skill == Type)
				{
					skill.m_level = BloodRules.Clamp(level, 100f);
					skill.m_accumulator = 0f;
					break;
				}
			}
		}
	}
}
namespace Vampirizm.Persistence
{
	public enum SaveReadResult
	{
		Missing,
		Loaded,
		Migrated,
		Invalid,
		UnsupportedVersion
	}
	public static class VampireSaveData
	{
		public const string Key = "com.igentuman.vampirizm.state";

		public const int CurrentVersion = 1;

		public static string Serialize(VampireState state)
		{
			return "1|" + (state.IsVampire ? "1|" : "0|") + state.Blood.ToString("R", CultureInfo.InvariantCulture);
		}

		public static SaveReadResult Read(IDictionary<string, string> data, out VampireState state)
		{
			state = new VampireState();
			if (!data.TryGetValue("com.igentuman.vampirizm.state", out var value))
			{
				return SaveReadResult.Missing;
			}
			if (string.IsNullOrEmpty(value))
			{
				return SaveReadResult.Invalid;
			}
			string[] array = value.Split(new char[1] { '|' });
			if (!int.TryParse(array[0], NumberStyles.None, CultureInfo.InvariantCulture, out var result))
			{
				return SaveReadResult.Invalid;
			}
			if (result > 1)
			{
				return SaveReadResult.UnsupportedVersion;
			}
			if (array.Length != 3)
			{
				return SaveReadResult.Invalid;
			}
			bool result2;
			if (result == 0)
			{
				if (!bool.TryParse(array[1], out result2))
				{
					return SaveReadResult.Invalid;
				}
			}
			else
			{
				if (array[1] != "0" && array[1] != "1")
				{
					return SaveReadResult.Invalid;
				}
				result2 = array[1] == "1";
			}
			if (!float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) || !BloodRules.IsFinite(result3))
			{
				return SaveReadResult.Invalid;
			}
			state = new VampireState(result2, result3);
			if (result != 0)
			{
				return SaveReadResult.Loaded;
			}
			return SaveReadResult.Migrated;
		}
	}
}
namespace Vampirizm.Patches
{
	[HarmonyPatch]
	internal static class AbilityPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerController), "TakeInput")]
		private static void AfterTakeInput(PlayerController __instance, bool __result)
		{
			if (!((Object)(object)__instance == (Object)null))
			{
				Player component = ((Component)__instance).GetComponent<Player>();
				if ((Object)(object)component == (Object)(object)Player.m_localPlayer)
				{
					((Component)component).GetComponent<VampireController>()?.BatForm.SetInputAllowed(__result);
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(Player), "SetControls")]
		private static void BeforeSetControls(Player __instance, ref Vector3 movedir, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold, ref bool block, ref bool blockHold, ref bool jump, ref bool crouch, ref bool run, ref bool autoRun, ref bool dodge)
		{
			//IL_0033: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			VampireController component = ((Component)__instance).GetComponent<VampireController>();
			if (!((Object)(object)component == (Object)null))
			{
				if (component.BatForm.Active)
				{
					component.BatForm.SetControls(movedir, run);
					attack = (attackHold = false);
					block = (blockHold = false);
					dodge = (run = (autoRun = false));
					jump = (crouch = false);
				}
				else if (component.Dash.Active)
				{
					movedir = Vector3.zero;
					attack = (attackHold = false);
					secondaryAttack = (secondaryAttackHold = false);
					block = (blockHold = false);
					jump = (autoRun = (dodge = false));
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "UpdateWalking")]
		private static void AfterUpdateWalking(Character __instance, float dt)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				((Component)__instance).GetComponent<VampireController>()?.Dash.FixedStep(dt);
				((Component)__instance).GetComponent<VampireController>()?.BatForm.FixedStep();
			}
		}
	}
	[HarmonyPatch]
	internal static class BatFormPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Humanoid), "UseItem")]
		private static bool BeforeUseItem(Humanoid __instance)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null && (Object)(object)val == (Object)(object)Player.m_localPlayer)
			{
				return !(((Component)val).GetComponent<VampireController>()?.BatForm.Active ?? false);
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "Interact")]
		private static bool BeforeInteract(Player __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				VampireController component = ((Component)__instance).GetComponent<VampireController>();
				if (component == null)
				{
					return true;
				}
				return !component.BatForm.Active;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		private static bool BeforeUpdatePlacement(Player __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				VampireController component = ((Component)__instance).GetComponent<VampireController>();
				if (component == null)
				{
					return true;
				}
				return !component.BatForm.Active;
			}
			return true;
		}
	}
	[HarmonyPatch]
	internal static class BitePatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "SetControls")]
		private static void BeforeSetControls(Player __instance, ref Vector3 movedir, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold, ref bool block, ref bool blockHold, ref bool jump, ref bool crouch, ref bool dodge, ItemData ___m_rightItem, ItemData ___m_leftItem)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			VampireController component = ((Component)__instance).GetComponent<VampireController>();
			if ((Object)(object)component == (Object)null || !component.IsActiveVampire)
			{
				return;
			}
			bool flag = ___m_rightItem == null && ___m_leftItem == null;
			bool active = component.BatForm.Active;
			if (flag || active || component.Drain.Active)
			{
				component.Drain.Input((flag || active) & secondaryAttack);
				secondaryAttack = false;
				secondaryAttackHold = false;
			}
			if (component.Drain.Active)
			{
				if (active)
				{
					component.BatForm.SetControls(Vector3.zero, run: false);
				}
				movedir = Vector3.zero;
				attack = (attackHold = false);
				block = (blockHold = false);
				jump = (crouch = false);
				dodge = false;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "Awake")]
		private static void AfterCharacterAwake(Character __instance)
		{
			DrainNetwork.RegisterCharacter(__instance);
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null)
			{
				RitualEffect.Register(val);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Game), "Start")]
		private static void AfterGameStart()
		{
			DrainNetwork.RegisterRouted();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(BaseAI), "UpdateAI")]
		private static bool BeforeBaseAI(BaseAI __instance, ref bool __result)
		{
			return Hold(__instance, ref __result);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MonsterAI), "UpdateAI")]
		private static bool BeforeMonsterAI(BaseAI __instance, ref bool __result)
		{
			return Hold(__instance, ref __result);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(AnimalAI), "UpdateAI")]
		private static bool BeforeAnimalAI(BaseAI __instance, ref bool __result)
		{
			return Hold(__instance, ref __result);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "CustomFixedUpdate")]
		private static void AfterCharacterFixedUpdate(Character __instance, float dt)
		{
			DrainVictim drainVictim = default(DrainVictim);
			if (((Component)__instance).TryGetComponent<DrainVictim>(ref drainVictim))
			{
				drainVictim.FixedStep(dt);
			}
		}

		private static bool Hold(BaseAI ai, ref bool result)
		{
			if (!DrainVictim.IsHeld((Component)(object)ai))
			{
				return true;
			}
			ai.StopMoving();
			result = false;
			return false;
		}
	}
	[HarmonyPatch]
	internal static class ColdPatches
	{
		internal struct EnvFlags
		{
			internal bool Hidden;

			internal bool Cold;

			internal bool Freezing;
		}

		private static readonly FieldInfo Cold = AccessTools.Field(typeof(EnvMan), "s_isCold");

		private static readonly FieldInfo Freezing = AccessTools.Field(typeof(EnvMan), "s_isFreezing");

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "UpdateEnvStatusEffects")]
		private static void BeforeUpdateEnvStatusEffects(Player __instance, out EnvFlags __state)
		{
			__state = default(EnvFlags);
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				VampireController component = ((Component)__instance).GetComponent<VampireController>();
				if (!((Object)(object)component == (Object)null) && component.IsActiveVampire)
				{
					__state = new EnvFlags
					{
						Hidden = true,
						Cold = EnvMan.IsCold(),
						Freezing = EnvMan.IsFreezing()
					};
					Cold.SetValue(null, false);
					Freezing.SetValue(null, false);
				}
			}
		}

		[HarmonyFinalizer]
		[HarmonyPatch(typeof(Player), "UpdateEnvStatusEffects")]
		private static Exception AfterUpdateEnvStatusEffects(Exception __exception, EnvFlags __state)
		{
			if (__state.Hidden)
			{
				Cold.SetValue(null, __state.Cold);
				Freezing.SetValue(null, __state.Freezing);
			}
			return __exception;
		}
	}
	[HarmonyPatch]
	internal static class DamagePatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
		private static void BeforeMelee(ItemData ___m_weapon, ItemData ___m_ammoItem, out bool __state)
		{
			__state = HitSource.Enter(___m_weapon, ___m_ammoItem);
		}

		[HarmonyFinalizer]
		[HarmonyPatch(typeof(Attack), "DoMeleeAttack")]
		private static Exception AfterMelee(Exception __exception, bool __state)
		{
			return Leave(__exception, __state);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Attack), "DoAreaAttack")]
		private static void BeforeArea(ItemData ___m_weapon, ItemData ___m_ammoItem, out bool __state)
		{
			__state = HitSource.Enter(___m_weapon, ___m_ammoItem);
		}

		[HarmonyFinalizer]
		[HarmonyPatch(typeof(Attack), "DoAreaAttack")]
		private static Exception AfterArea(Exception __exception, bool __state)
		{
			return Leave(__exception, __state);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Projectile), "OnHit")]
		private static void BeforeProjectile(ItemData ___m_weapon, ItemData ___m_ammo, out bool __state)
		{
			__state = HitSource.Enter(___m_weapon, ___m_ammo);
		}

		[HarmonyFinalizer]
		[HarmonyPatch(typeof(Projectile), "OnHit")]
		private static Exception AfterProjectile(Exception __exception, bool __state)
		{
			return Leave(__exception, __state);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Projectile), "DoAOE")]
		private static void BeforeProjectileAoe(ItemData ___m_weapon, ItemData ___m_ammo, out bool __state)
		{
			__state = HitSource.Enter(___m_weapon, ___m_ammo);
		}

		[HarmonyFinalizer]
		[HarmonyPatch(typeof(Projectile), "DoAOE")]
		private static Exception AfterProjectileAoe(Exception __exception, bool __state)
		{
			return Leave(__exception, __state);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Aoe), "OnHit")]
		private static void BeforeAoe(ItemData ___m_itemData, ItemData ___m_ammo, out bool __state)
		{
			__state = HitSource.Enter(___m_itemData, ___m_ammo);
		}

		[HarmonyFinalizer]
		[HarmonyPatch(typeof(Aoe), "OnHit")]
		private static Exception AfterAoe(Exception __exception, bool __state)
		{
			return Leave(__exception, __state);
		}

		private static Exception Leave(Exception exception, bool state)
		{
			HitSource.Exit(state);
			return exception;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Attack), "ModifyDamage")]
		private static void AfterModifyDamage(HitData hitData, Humanoid ___m_character, ItemData ___m_weapon)
		{
			if (hitData == null || (Object)(object)Plugin.Instance == (Object)null)
			{
				return;
			}
			Player val = (Player)(object)((___m_character is Player) ? ___m_character : null);
			if (val != null && ___m_weapon != null && !((Object)(object)((Humanoid)val).m_unarmedWeapon == (Object)null) && ___m_weapon == ((Humanoid)val).m_unarmedWeapon.m_itemData && VampireNetwork.IsVampire(val))
			{
				float num = VampireDamageRules.UnarmedMultiplier(VampirismSkill.Level(val), Plugin.Instance.Settings.UnarmedDamageMultiplier.Value);
				if (num != 1f)
				{
					((DamageTypes)(ref hitData.m_damage)).Modify(num);
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "Damage")]
		private static void BeforeDamage(Character __instance, ref HitData hit)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && hit != null)
			{
				((Component)__instance).GetComponent<VampireController>()?.Invisibility.End();
			}
			if (hit == null || (Object)(object)Plugin.Instance == (Object)null)
			{
				return;
			}
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null && VampireNetwork.IsVampire(val))
			{
				VampireConfig settings = Plugin.Instance.Settings;
				DamageScale damageScale = VampireDamageRules.Scale(HitSource.IsSilver, hit.m_damage.m_spirit > 0f, settings.SpiritDamageRule.Value, settings.WeaknessMultiplier.Value);
				if (!damageScale.IsIdentity)
				{
					hit = hit.Clone();
					((DamageTypes)(ref hit.m_damage)).Modify(damageScale.Whole);
					hit.m_damage.m_spirit *= damageScale.Spirit;
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class DeathPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "OnDeath")]
		private static void BeforeDeath(Player __instance)
		{
			((Component)__instance).GetComponent<VampireController>()?.OnDeath();
		}
	}
	[HarmonyPatch]
	internal static class EitrPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })]
		private static void BeforeUpdateStats(Player __instance, out float __state)
		{
			__state = __instance.m_eiterRegen;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "UpdateFood")]
		private static void AfterUpdateFood(Player __instance, bool forceUpdate)
		{
			if (!forceUpdate && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				VampireController component = ((Component)__instance).GetComponent<VampireController>();
				if ((Object)(object)component != (Object)null && component.IsActiveVampire)
				{
					component.ApplyEitrRegen();
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })]
		private static void AfterUpdateStats(Player __instance, float __state)
		{
			__instance.m_eiterRegen = __state;
		}
	}
	[HarmonyPatch]
	internal static class FoodDebugPatches
	{
		private static int _lastCount = -1;

		private static string Foods(Player player)
		{
			return string.Join(", ", from f in player.GetFoods()
				select $"{f.m_name}:{f.m_time:0.0}/{f.m_item.m_shared.m_foodBurnTime:0}");
		}

		private static bool Local(Player player)
		{
			if ((Object)(object)player != (Object)null)
			{
				return (Object)(object)player == (Object)(object)Player.m_localPlayer;
			}
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(Humanoid), "UseItem")]
		private static void LogUseItem(Humanoid __instance, ItemData item)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null && Local(val) && item != null)
			{
				GameObject dropPrefab = item.m_dropPrefab;
				Plugin.LogInfo($"[FoodDebug] UseItem {((dropPrefab != null) ? ((Object)dropPrefab).name : null)} type={item.m_shared.m_itemType} food={item.m_shared.m_food} " + "foods=[" + Foods(val) + "]");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "CanConsumeItem")]
		private static void LogCanConsume(Player __instance, ItemData item, bool __result)
		{
			if (Local(__instance))
			{
				object arg;
				if (item == null)
				{
					arg = null;
				}
				else
				{
					GameObject dropPrefab = item.m_dropPrefab;
					arg = ((dropPrefab != null) ? ((Object)dropPrefab).name : null);
				}
				Plugin.LogInfo($"[FoodDebug] CanConsumeItem {arg} => {__result}");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "CanEat")]
		private static void LogCanEat(Player __instance, ItemData item, bool __result)
		{
			if (Local(__instance))
			{
				object arg;
				if (item == null)
				{
					arg = null;
				}
				else
				{
					GameObject dropPrefab = item.m_dropPrefab;
					arg = ((dropPrefab != null) ? ((Object)dropPrefab).name : null);
				}
				Plugin.LogInfo($"[FoodDebug] CanEat {arg} => {__result} foods=[{Foods(__instance)}]");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "EatFood")]
		private static void LogEatFood(Player __instance, ItemData item, bool __result)
		{
			if (Local(__instance))
			{
				object arg;
				if (item == null)
				{
					arg = null;
				}
				else
				{
					GameObject dropPrefab = item.m_dropPrefab;
					arg = ((dropPrefab != null) ? ((Object)dropPrefab).name : null);
				}
				Plugin.LogInfo($"[FoodDebug] EatFood {arg} => {__result} foods=[{Foods(__instance)}]");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "ClearFood")]
		private static void LogClearFood(Player __instance)
		{
			if (Local(__instance))
			{
				Plugin.LogInfo("[FoodDebug] ClearFood\n" + Environment.StackTrace);
			}
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(Player), "UpdateFood")]
		private static void LogUpdateFood(Player __instance, bool forceUpdate)
		{
			if (Local(__instance))
			{
				int count = __instance.GetFoods().Count;
				if (count != _lastCount)
				{
					Plugin.LogInfo($"[FoodDebug] food count {_lastCount} -> {count} (force={forceUpdate}) foods=[{Foods(__instance)}]");
				}
				_lastCount = count;
			}
		}
	}
	[HarmonyPatch]
	internal static class FoodPatches
	{
		private static VampireController ActiveVampire(Character character)
		{
			Player val = (Player)(object)((character is Player) ? character : null);
			if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return null;
			}
			VampireController component = ((Component)val).GetComponent<VampireController>();
			if (!((Object)(object)component != (Object)null) || !component.IsActiveVampire)
			{
				return null;
			}
			return component;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Humanoid), "UseItem")]
		private static bool BeforeUseItem(Humanoid __instance, Inventory inventory, ItemData item, bool fromInventoryGui)
		{
			if (item != null && !((Object)(object)Plugin.Instance == (Object)null))
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer))
				{
					bool flag = VampireRune.IsRune(item);
					bool flag2 = !flag && (Object)(object)ActiveVampire((Character)(object)val) != (Object)null && BloodItemRegistry.IsBloodItem(item);
					bool flag3 = !flag && !flag2 && (Object)(object)ActiveVampire((Character)(object)val) != (Object)null && SlimeProtection.IsSlimeItem(item);
					if (!flag && !flag2 && !flag3)
					{
						return true;
					}
					if (inventory == null)
					{
						inventory = ((Humanoid)val).GetInventory();
					}
					if (!inventory.ContainsItem(item))
					{
						return true;
					}
					if (!fromInventoryGui)
					{
						GameObject hoverObject = ((Humanoid)val).GetHoverObject();
						if ((Object)(object)hoverObject != (Object)null && hoverObject.GetComponentInParent<Interactable>() != null)
						{
							return true;
						}
					}
					if (flag)
					{
						return !VampireConversion.TryRitual(val, inventory, item);
					}
					if (!flag2)
					{
						return !SlimeProtection.TryApply(val, inventory, item);
					}
					return !BloodFeeding.TryDrink(val, inventory, item);
				}
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "CanConsumeItem")]
		private static bool BeforeCanConsumeItem(Player __instance, ItemData item, ref bool __result)
		{
			if (item == null || (Object)(object)ActiveVampire((Character)(object)__instance) == (Object)null)
			{
				return true;
			}
			if (BloodItemRegistry.IsBloodItem(item))
			{
				__result = true;
				return false;
			}
			if (!BloodItemRegistry.IsForbiddenConsumable(item))
			{
				return true;
			}
			((Character)__instance).Message((MessageType)2, "$vampirizm_food_forbidden", 0, (Sprite)null, false);
			__result = false;
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "EatFood")]
		private static bool BeforeEatFood(Player __instance, ItemData item, ref bool __result)
		{
			if (item == null || (Object)(object)ActiveVampire((Character)(object)__instance) == (Object)null)
			{
				return true;
			}
			__result = BloodItemRegistry.IsBloodItem(item) && BloodFeeding.TryDrink(__instance, ((Humanoid)__instance).GetInventory(), item);
			return false;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "GetTotalFoodValue")]
		private static void AfterGetTotalFoodValue(Player __instance, ref float hp, ref float stamina, ref float eitr)
		{
			ActiveVampire((Character)(object)__instance)?.ApplyFoodValues(ref hp, ref stamina, ref eitr);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "UpdateFood")]
		private static void AfterUpdateFood(Player __instance, float dt, bool forceUpdate)
		{
			if (!forceUpdate)
			{
				ActiveVampire((Character)(object)__instance)?.TickFood(dt);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
		{
			typeof(ItemData),
			typeof(int),
			typeof(bool),
			typeof(float),
			typeof(int),
			typeof(bool)
		})]
		private static void AfterGetTooltip(ItemData item, ref string __result)
		{
			string text = BloodFeeding.Tooltip(item);
			if (text != null)
			{
				__result = __result + "\n" + text;
			}
		}
	}
	[HarmonyPatch]
	internal static class FriendlyPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(BaseAI), "IsEnemy", new Type[]
		{
			typeof(Character),
			typeof(Character)
		})]
		private static void AfterIsEnemy(Character a, Character b, ref bool __result)
		{
			if (__result && (Object)(object)Plugin.Instance != (Object)null && FriendlyRegistry.IsFriendlyTo(a, b))
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch]
	internal static class HudPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Hud), "Awake")]
		private static void AfterHudAwake(Hud __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<BloodHud>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<BloodHud>();
			}
		}
	}
	[HarmonyPatch]
	internal static class InvisibilityPatches
	{
		private static readonly FieldRef<MonsterAI, Character> MonsterTarget = AccessTools.FieldRefAccess<MonsterAI, Character>("m_targetCreature");

		private static readonly FieldRef<AnimalAI, Character> AnimalTarget = AccessTools.FieldRefAccess<AnimalAI, Character>("m_target");

		private static readonly MethodInfo ClearMonsterTarget = AccessTools.Method(typeof(MonsterAI), "SetTarget", (Type[])null, (Type[])null);

		[HarmonyPrefix]
		[HarmonyPatch(typeof(VisEquipment), "UpdateVisuals")]
		private static void BeforeEquipmentVisuals(VisEquipment __instance)
		{
			Player val = __instance.m_playerComponent;
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)__instance).GetComponent<Player>();
			}
			if ((Object)(object)val != (Object)null)
			{
				((Component)val).GetComponent<VampireController>()?.Invisibility?.BeforeEquipmentUpdate();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Character), "SetVisible")]
		private static void BeforeSetVisible(Character __instance, ref bool visible)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null && (Object)(object)val != (Object)(object)Player.m_localPlayer && VampireNetwork.IsInvisible(val))
			{
				visible = false;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Character), "Awake")]
		private static void AfterCharacterAwake(Character __instance)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null)
			{
				VampireController.Ensure(val);
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Humanoid), "UseItem")]
		private static void BeforeUseItem(Humanoid __instance)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null && (Object)(object)val == (Object)(object)Player.m_localPlayer)
			{
				((Component)val).GetComponent<VampireController>()?.Invisibility.End();
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "GetHoverName")]
		private static bool BeforeGetHoverName(Player __instance, ref string __result)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer && VampireNetwork.IsInvisible(__instance))
			{
				__result = "";
				return false;
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "OnTargeted")]
		private static bool BeforeOnTargeted(Player __instance)
		{
			if (!((Object)(object)__instance == (Object)(object)Player.m_localPlayer))
			{
				return !VampireNetwork.IsInvisible(__instance);
			}
			return true;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Hud), "UpdateCrosshair")]
		private static void BeforeUpdateCrosshair(ref Player __0)
		{
			if ((Object)(object)__0 != (Object)null && (Object)(object)__0 != (Object)(object)Player.m_localPlayer && VampireNetwork.IsInvisible(__0))
			{
				__0 = null;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(BaseAI), "CanSenseTarget", new Type[] { typeof(Character) })]
		private static bool BeforeCanSenseTarget(Character target, ref bool __result)
		{
			return NotInvisible(target, ref __result);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(BaseAI), "CanSeeTarget", new Type[] { typeof(Character) })]
		private static bool BeforeCanSeeTarget(Character target, ref bool __result)
		{
			return NotInvisible(target, ref __result);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(BaseAI), "CanHearTarget", new Type[] { typeof(Character) })]
		private static bool BeforeCanHearTarget(Character target, ref bool __result)
		{
			return NotInvisible(target, ref __result);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(BaseAI), "GetTargetCreature")]
		private static void AfterGetBaseTarget(ref Character __result)
		{
			Character obj = __result;
			Player val = (Player)(object)((obj is Player) ? obj : null);
			if (val != null && VampireNetwork.IsInvisible(val))
			{
				__result = null;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(MonsterAI), "GetTargetCreature")]
		private static void AfterGetMonsterTarget(ref Character __result)
		{
			Character obj = __result;
			Player val = (Player)(object)((obj is Player) ? obj : null);
			if (val != null && VampireNetwork.IsInvisible(val))
			{
				__result = null;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MonsterAI), "SetTarget")]
		private static bool BeforeSetMonsterTarget(Character attacker)
		{
			Player val = (Player)(object)((attacker is Player) ? attacker : null);
			if (val != null)
			{
				return !VampireNetwork.IsInvisible(val);
			}
			return true;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(MonsterAI), "UpdateAI")]
		private static void AfterMonsterAi(MonsterAI __instance)
		{
			Character obj = MonsterTarget.Invoke(__instance);
			Player val = (Player)(object)((obj is Player) ? obj : null);
			if (val != null && VampireNetwork.IsInvisible(val))
			{
				ClearMonsterTarget.Invoke(__instance, new object[1]);
				((BaseAI)__instance).StopMoving();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(AnimalAI), "UpdateAI")]
		private static void AfterAnimalAi(AnimalAI __instance)
		{
			Character obj = AnimalTarget.Invoke(__instance);
			Player val = (Player)(object)((obj is Player) ? obj : null);
			if (val != null && VampireNetwork.IsInvisible(val))
			{
				AnimalTarget.Invoke(__instance) = null;
				((BaseAI)__instance).StopMoving();
			}
		}

		private static bool NotInvisible(Character target, ref bool result)
		{
			Player val = (Player)(object)((target is Player) ? target : null);
			if (val == null || !VampireNetwork.IsInvisible(val))
			{
				return true;
			}
			result = false;
			return false;
		}
	}
	[HarmonyPatch]
	internal static class PlayerPersistencePatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "Load")]
		private static void AfterLoad(Player __instance)
		{
			VampireController.Ensure(__instance).LoadState();
			VampireFood.Rewrap(__instance);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "SetLocalPlayer")]
		private static void AfterSetLocalPlayer(Player __instance)
		{
			VampireController.Ensure(__instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "Save")]
		private static void BeforeSave(Player __instance)
		{
			((Component)__instance).GetComponent<VampireController>()?.SaveState();
		}
	}
	[HarmonyPatch]
	internal static class SleepPatches
	{
		private const double SleepRetrySeconds = 10.0;

		private const double SkipDurationSeconds = 12.0;

		private static readonly FieldRef<Game, bool> GameSleeping = AccessTools.FieldRefAccess<Game, bool>("m_sleeping");

		private static readonly FieldRef<Game, double> LastSleepTime = AccessTools.FieldRefAccess<Game, double>("m_lastSleepTime");

		private static readonly FieldRef<EnvMan, bool> SkipTime = AccessTools.FieldRefAccess<EnvMan, bool>("m_skipTime");

		private static readonly FieldRef<EnvMan, double> SkipToTime = AccessTools.FieldRefAccess<EnvMan, double>("m_skipToTime");

		private static readonly FieldRef<EnvMan, double> TimeSkipSpeed = AccessTools.FieldRefAccess<EnvMan, double>("m_timeSkipSpeed");

		[HarmonyPostfix]
		[HarmonyPatch(typeof(EnvMan), "CalculateCanSleep")]
		private static void AfterCalculateCanSleep(EnvMan __instance, ref bool __result)
		{
			if (__result)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)ZNet.instance == (Object)null))
			{
				VampireController component = ((Component)localPlayer).GetComponent<VampireController>();
				if (!((Object)(object)component == (Object)null) && component.IsActiveVampire && SleepRules.IsDaySleep(__instance.GetDayFraction()))
				{
					__result = ZNet.instance.GetTimeSeconds() > localPlayer.m_wakeupTime + __instance.m_sleepCooldownSeconds;
				}
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Game), "UpdateSleeping")]
		private static bool BeforeUpdateSleeping(Game __instance)
		{
			if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || GameSleeping.Invoke(__instance))
			{
				return true;
			}
			EnvMan instance = EnvMan.instance;
			if ((Object)(object)instance == (Object)null || instance.IsTimeSkipping() || !SleepRules.IsDaySleep(instance.GetDayFraction()))
			{
				return true;
			}
			double timeSeconds = ZNet.instance.GetTimeSeconds();
			if (timeSeconds - LastSleepTime.Invoke(__instance) < 10.0 || !EveryoneIsVampireInBed())
			{
				return true;
			}
			double num = SleepRules.DuskTime(timeSeconds, instance.m_dayLengthSec);
			SkipToTime.Invoke(instance) = num;
			TimeSkipSpeed.Invoke(instance) = (num - timeSeconds) / 12.0;
			SkipTime.Invoke(instance) = true;
			GameSleeping.Invoke(__instance) = true;
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, "SleepStart", Array.Empty<object>());
			Plugin.LogInfo($"Vampire day sleep: time {timeSeconds:0}, skipping to dusk {num:0}");
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "SetSleeping")]
		private static void BeforeSetSleeping(Player __instance, out bool __state)
		{
			__state = __instance.IsSleeping();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "SetSleeping")]
		private static void AfterSetSleeping(Player __instance, bool sleep, bool __state)
		{
			if (!(!__state || sleep) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Object)(object)EnvMan.instance == (Object)null))
			{
				VampireController component = ((Component)__instance).GetComponent<VampireController>();
				if (!((Object)(object)component == (Object)null) && component.IsActiveVampire && SleepRules.IsDuskWake(EnvMan.instance.GetDayFraction()))
				{
					((Character)__instance).Message((MessageType)2, "$vampirizm_good_evening", 0, (Sprite)null, false);
				}
			}
		}

		private static bool EveryoneIsVampireInBed()
		{
			List<ZDO> allCharacterZDOS = ZNet.instance.GetAllCharacterZDOS();
			if (allCharacterZDOS.Count == 0)
			{
				return false;
			}
			foreach (ZDO item in allCharacterZDOS)
			{
				if (!item.GetBool(ZDOVars.s_inBed, false) || !item.GetBool("com.igentuman.vampirizm.vampire", false))
				{
					return false;
				}
			}
			return true;
		}
	}
}
namespace Vampirizm.Networking
{
	public enum DrainStatus
	{
		Ok,
		Rejected,
		TooFar,
		NotDonor,
		Dead,
		Busy,
		Stale,
		Expired
	}
	internal static class DrainNetwork
	{
		internal const string DrainRpc = "Vampirizm_Drain";

		internal const string DrainResultRpc = "Vampirizm_DrainResult";

		internal const string BiteRpc = "Vampirizm_Bite";

		internal const string BiteResultRpc = "Vampirizm_BiteResult";

		internal const string ReleaseRpc = "Vampirizm_DrainRelease";

		internal const string DrainedKey = "com.igentuman.vampirizm.drained";

		private const float DistanceTolerance = 2f;

		private static ZRoutedRpc _registeredOn;

		internal static void RegisterCharacter(Character character)
		{
			ZNetView component = ((Component)character).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || component.GetZDO() == null)
			{
				return;
			}
			Player player = default(Player);
			ref Player reference = ref player;
			Character obj = character;
			reference = (Player)(object)((obj is Player) ? obj : null);
			if (player != null)
			{
				component.Register<ZPackage>("Vampirizm_Bite", (Action<long, ZPackage>)delegate(long sender, ZPackage package)
				{
					OnBite(player, sender, package);
				});
				return;
			}
			component.Register<ZPackage>("Vampirizm_Drain", (Action<long, ZPackage>)delegate(long sender, ZPackage package)
			{
				OnDrain(character, sender, package);
			});
			component.Register<ZPackage>("Vampirizm_DrainRelease", (Action<long, ZPackage>)delegate(long sender, ZPackage package)
			{
				OnRelease(character, sender, package);
			});
		}

		internal static void RegisterRouted()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null && instance != _registeredOn)
			{
				_registeredOn = instance;
				instance.Register<ZPackage>("Vampirizm_DrainResult", (Action<long, ZPackage>)OnDrainResult);
				instance.Register<ZPackage>("Vampirizm_BiteResult", (Action<long, ZPackage>)OnBiteResult);
			}
		}

		internal static float Timeout(float interval)
		{
			return interval * 2.5f + 1f;
		}

		internal static void RequestDrain(Character target, ZDOID attacker, int session, int tick)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			ZPackage val = new ZPackage();
			val.Write(attacker);
			val.Write(session);
			val.Write(tick);
			((Component)target).GetComponent<ZNetView>().InvokeRPC("Vampirizm_Drain", new object[1] { val });
		}

		internal static void RequestRelease(Character target, int session)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Expected O, but got Unknown
			ZNetView val = (((Object)(object)target != (Object)null) ? ((Component)target).GetComponent<ZNetView>() : null);
			if (!((Object)(object)val == (Object)null) && val.IsValid())
			{
				ZPackage val2 = new ZPackage();
				val2.Write(session);
				val.InvokeRPC("Vampirizm_DrainRelease", new object[1] { val2 });
			}
		}

		internal static void RequestBite(Player target, ZDOID attacker, string attackerName)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			ZPackage val = new ZPackage();
			val.Write(attacker);
			val.Write(attackerName ?? "");
			((Component)target).GetComponent<ZNetView>().InvokeRPC("Vampirizm_Bite", new object[1] { val });
		}

		private static bool Authenticate(long sender, ZDOID attacker, Vector3 victimPosition, out ZDO attackerZdo)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_005b: Unknown result type (might be due to invalid IL or missing references)
			ZDOMan instance = ZDOMan.instance;
			attackerZdo = ((instance != null) ? instance.GetZDO(attacker) : null);
			if (attackerZdo == null || attackerZdo.GetOwner() != sender || !attackerZdo.GetBool("com.igentuman.vampirizm.vampire", false))
			{
				return false;
			}
			float num = Plugin.Instance.Settings.BiteRange.Value + 2f;
			Vector3 val = attackerZdo.GetPosition() - victimPosition;
			return ((Vector3)(ref val)).sqrMagnitude <= num * num;
		}

		private static void OnDrain(Character victim, long sender, ZPackage package)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			ZNetView component = ((Component)victim).GetComponent<ZNetView>();
			if (!((Object)(object)Plugin.Instance == (Object)null) && !((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner())
			{
				ZDOID attacker = package.ReadZDOID();
				int num = package.ReadInt();
				int num2 = package.ReadInt();
				float blood;
				bool xpAllowed;
				bool died;
				DrainStatus drainStatus = Drain(victim, component, sender, attacker, num, num2, out blood, out xpAllowed, out died);
				ZPackage val = new ZPackage();
				val.Write(num);
				val.Write(num2);
				val.Write((int)drainStatus);
				val.Write(blood);
				val.Write(xpAllowed);
				val.Write(died);
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "Vampirizm_DrainResult", new object[1] { val });
			}
		}

		private static DrainStatus Drain(Character victim, ZNetView view, long sender, ZDOID attacker, int session, int tick, out float blood, out bool xpAllowed, out bool died)
		{
			//IL_0033: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: 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_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: 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_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			blood = 0f;
			xpAllowed = false;
			died = false;
			VampireConfig settings = Plugin.Instance.Settings;
			if (victim.IsDead() || victim.GetHealth() <= 0f)
			{
				return DrainStatus.Dead;
			}
			if (!Authenticate(sender, attacker, ((Component)victim).transform.position, out var attackerZdo))
			{
				ZDOMan instance = ZDOMan.instance;
				ZDO val = ((instance != null) ? instance.GetZDO(attacker) : null);
				if (val == null || val.GetOwner() != sender || !val.GetBool("com.igentuman.vampirizm.vampire", false))
				{
					return DrainStatus.Rejected;
				}
				return DrainStatus.TooFar;
			}
			if (!DonorRegistry.CanFeed(victim))
			{
				return DrainStatus.NotDonor;
			}
			DrainVictim drainVictim = DrainVictim.Ensure(victim);
			float value = settings.BiteInterval.Value;
			int maxTicks = DrainRules.SessionTicks(settings.BiteMaxDuration.Value, value) + 1;
			switch (drainVictim.Ledger.Accept(sender, session, tick, Time.time, Timeout(value), maxTicks))
			{
			default:
				return DrainStatus.Expired;
			case DrainVerdict.Stale:
				return DrainStatus.Stale;
			case DrainVerdict.Busy:
				return DrainStatus.Busy;
			case DrainVerdict.Accepted:
			{
				drainVictim.Held = DonorRegistry.CanHold(victim);
				bool flag = attackerZdo.GetBool("com.igentuman.vampirizm.batform", false);
				drainVictim.SetGlue((drainVictim.Held && !flag) ? attacker : ZDOID.None);
				if (tick <= 1)
				{
					return DrainStatus.Ok;
				}
				float health = victim.GetHealth();
				HitData val2 = new HitData();
				float num = (flag ? settings.BatBiteDamage.Value : settings.BiteDamage.Value);
				val2.m_damage.m_damage = DrainRules.DealtDamage(num, health);
				val2.m_attacker = attacker;
				val2.m_hitType = (HitType)2;
				val2.m_point = victim.GetCenterPoint();
				Vector3 val3 = ((Component)victim).transform.position - ZDOMan.instance.GetZDO(attacker).GetPosition();
				val2.m_dir = ((Vector3)(ref val3)).normalized;
				victim.Damage(val2);
				float num2 = Mathf.Max(0f, health - victim.GetHealth());
				blood = (flag ? (settings.BatBiteBlood.Value * Mathf.Clamp01(num2 / Mathf.Max(0.1f, num))) : DrainRules.Blood(num2, settings.BloodPerDamage.Value));
				ZDO zDO = view.GetZDO();
				float num3 = zDO.GetFloat("com.igentuman.vampirizm.drained", 0f) + num2;
				zDO.Set("com.igentuman.vampirizm.drained", num3);
				xpAllowed = num3 <= victim.GetMaxHealth();
				died = victim.IsDead() || victim.GetHealth() <= 0f;
				if (died)
				{
					drainVictim.Release();
				}
				return DrainStatus.Ok;
			}
			}
		}

		private static void OnRelease(Character victim, long sender, ZPackage package)
		{
			ZNetView component = ((Component)victim).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner())
			{
				int num = package.ReadInt();
				DrainVictim component2 = ((Component)victim).GetComponent<DrainVictim>();
				if ((Object)(object)component2 != (Object)null && component2.Ledger.Attacker == sender && component2.Ledger.Session == num)
				{
					component2.Release();
				}
			}
		}

		private static void OnBite(Player victim, long sender, ZPackage package)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			if (!((Object)(object)Plugin.Instance == (Object)null) && !((Object)(object)victim != (Object)(object)Player.m_localPlayer))
			{
				ZDOID attacker = package.ReadZDOID();
				string attackerName = package.ReadString();
				ZDO attackerZdo;
				BiteConversionResult biteConversionResult = (Authenticate(sender, attacker, ((Component)victim).transform.position, out attackerZdo) ? VampireConversion.AcceptBite(victim, attackerName) : BiteConversionResult.Rejected);
				ZPackage val = new ZPackage();
				val.Write((int)biteConversionResult);
				val.Write(victim.GetPlayerName());
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "Vampirizm_BiteResult", new object[1] { val });
			}
		}

		private static void OnDrainResult(long sender, ZPackage package)
		{
			VampireController local = VampireController.Local;
			if (!((Object)(object)local == (Object)null))
			{
				int session = package.ReadInt();
				int tick = package.ReadInt();
				DrainStatus status = (DrainStatus)package.ReadInt();
				float blood = package.ReadSingle();
				bool xpAllowed = package.ReadBool();
				bool died = package.ReadBool();
				local.Drain.OnResult(session, tick, status, blood, xpAllowed, died);
			}
		}

		private static void OnBiteResult(long sender, ZPackage package)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				BiteConversionResult biteConversionResult = (BiteConversionResult)package.ReadInt();
				string text = package.ReadString();
				((Character)localPlayer).Message((MessageType)2, Localization.instance.Localize(biteConversionResult switch
				{
					BiteConversionResult.Converted => "$vampirizm_bite_converted", 
					BiteConversionResult.Refused => "$vampirizm_bite_refused", 
					BiteConversionResult.AlreadyVampire => "$vampirizm_bite_already", 
					BiteConversionResult.Disabled => "$vampirizm_bite_disabled", 
					_ => "$vampirizm_bite_failed", 
				}, new string[1] { text }), 0, (Sprite)null, false);
			}
		}
	}
	internal sealed class DrainVictim : MonoBehaviour
	{
		private const float MouthHeight = 1.45f;

		private const float BodyGap = 0.05f;

		private const float PullRate = 6f;

		private static readonly FieldRef<Character, Rigidbody> Body = AccessTools.FieldRefAccess<Character, Rigidbody>("m_body");

		private ZNetView _view;

		private Character _character;

		private ZDOID _glueTo = ZDOID.None;

		private Player _vampire;

		internal readonly DrainLedger Ledger = new DrainLedger();

		internal bool Held { get; set; }

		internal static DrainVictim Ensure(Character character)
		{
			return ((Component)character).GetComponent<DrainVictim>() ?? ((Component)character).gameObject.AddComponent<DrainVictim>();
		}

		internal static bool IsHeld(Component ai)
		{
			DrainVictim component = ai.GetComponent<DrainVictim>();
			if ((Object)(object)component != (Object)null)
			{
				return component.Held;
			}
			return false;
		}

		private void Awake()
		{
			_view = ((Component)this).GetComponent<ZNetView>();
			_character = ((Component)this).GetComponent<Character>();
		}

		internal void SetGlue(ZDOID vampire)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			if (!(vampire == _glueTo))
			{
				_glueTo = vampire;
				_vampire = null;
			}
		}

		internal void FixedStep(float dt)
		{
			//IL_00bf: 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_0063: 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_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			if (!Held || ((ZDOID)(ref _glueTo)).IsNone() || (Object)(object)_character == (Object)null || (Object)(object)_view == (Object)null || !_view.IsOwner())
			{
				return;
			}
			if ((Object)(object)_vampire == (Object)null)
			{
				GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.FindInstance(_glueTo) : null);
				_vampire = (((Object)(object)val != (Object)null) ? val.GetComponent<Player>() : null);
				if ((Object)(object)_vampire == (Object)null)
				{
					return;
				}
			}
			Rigidbody val2 = Body.Invoke(_character);
			if (!((Object)(object)val2 == (Object)null))
			{
				Vector3 forward = ((Component)_vampire).transform.forward;
				forward.y = 0f;
				if (!(((Vector3)(ref forward)).sqrMagnitude < 0.001f))
				{
					((Vector3)(ref forward)).Normalize();
					CapsuleCollider collider = _character.GetCollider();
					Vector3 lossyScale = ((Component)this).transform.lossyScale;
					Vector3 val3 = (((Object)(object)collider != (Object)null) ? Vector3.Scale(collider.center, lossyScale) : (Vector3.up * 0.5f));
					float num = (((Object)(object)collider == (Object)null) ? 0.3f : (((collider.direction == 0) ? (collider.height * 0.5f) : collider.radius) * lossyScale.x));
					Quaternion val4 = Quaternion.LookRotation(Vector3.Cross(Vector3.up, forward));
					Vector3 val5 = ((Component)_vampire).transform.position + Vector3.up * 1.45f + forward * (((Character)_vampire).GetRadius() + num + 0.05f) - val4 * val3;
					float num2 = 1f - Mathf.Exp(-6f * dt);
					val5 = Vector3.Lerp(val2.position, val5, num2);
					val4 = Quaternion.Slerp(val2.rotation, val4, num2);
					val2.position = val5;
					val2.rotation = val4;
					((Component)this).transform.SetPositionAndRotation(val5, val4);
					val2.linearVelocity = Vector3.zero;
					val2.angularVelocity = Vector3.zero;
				}
			}
		}

		private void Update()
		{
			if (Held)
			{
				float timeout = (((Object)(object)Plugin.Instance != (Object)null) ? DrainNetwork.Timeout(Plugin.Instance.Settings.BiteInterval.Value) : 0f);
				if ((Object)(object)_view == (Object)null || !_view.IsValid() || !_view.IsOwner() || !Ledger.IsActive(Time.time, timeout))
				{
					Release();
				}
			}
		}

		internal void Release()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			Ledger.Release();
			Held = false;
			SetGlue(ZDOID.None);
		}
	}
	internal static class VampireNetwork
	{
		internal const string VampireKey = "com.igentuman.vampirizm.vampire";

		internal const string BloodKey = "com.igentuman.vampirizm.blood";

		internal const string LevelKey = "com.igentuman.vampirizm.level";

		internal const string InvisibleKey = "com.igentuman.vampirizm.invisible";

		internal const string BatFormKey = "com.igentuman.vampirizm.batform";

		internal const string DrinkTargetKey = "com.igentuman.vampirizm.drinktarget";

		private static readonly KeyValuePair<int, int> DrinkTargetHash = ZDO.GetHashZDOID("com.igentuman.vampirizm.drinktarget");

		internal static void SetDrinkTarget(ZNetView view, ZDOID target)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)view == (Object)null) && view.IsValid() && view.IsOwner())
			{
				ZDO zDO = view.GetZDO();
				if (zDO.GetZDOID(DrinkTargetHash) != target)
				{
					zDO.Set(DrinkTargetHash, target);
				}
			}
		}

		internal static ZDOID GetDrinkTarget(ZNetView view)
		{
			//IL_0011: 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)
			if (!((Object)(object)view != (Object)null) || !view.IsValid())
			{
				return ZDOID.None;
			}
			return view.GetZDO().GetZDOID(DrinkTargetHash);
		}

		internal static void SetInvisible(ZNetView view, bool invisible)
		{
			if (!((Object)(object)view == (Object)null) && view.IsValid() && view.IsOwner())
			{
				ZDO zDO = view.GetZDO();
				if (zDO.GetBool("com.igentuman.vampirizm.invisible", false) != invisible)
				{
					zDO.Set("com.igentuman.vampirizm.invisible", invisible);
				}
			}
		}

		internal static bool IsInvisible(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			VampireController component = ((Component)player).GetComponent<VampireController>();
			if ((Object)(object)player == (Object)(object)Player.m_localPlayer && (Object)(object)component != (Object)null)
			{
				return component.Invisibility?.Active ?? false;
			}
			ZNetView component2 = ((Component)player).GetComponent<ZNetView>();
			if ((Object)(object)component2 != (Object)null && component2.IsValid())
			{
				return component2.GetZDO().GetBool("com.igentuman.vampirizm.invisible", false);
			}
			return false;
		}

		internal static void Publish(ZNetView view, VampireState state, float level)
		{
			if (view.IsValid() && view.IsOwner())
			{
				ZDO zDO = view.GetZDO();
				if (zDO.GetBool("com.igentuman.vampirizm.vampire", false) != state.IsVampire)
				{
					zDO.Set("com.igentuman.vampirizm.vampire", state.IsVampire);
				}
				if (zDO.GetFloat("com.igentuman.vampirizm.blood", 0f) != state.Blood)
				{
					zDO.Set("com.igentuman.vampirizm.blood", state.Blood);
				}
				if (zDO.GetFloat("com.igentuman.vampirizm.level", 0f) != level)
				{
					zDO.Set("com.igentuman.vampirizm.level", level);
				}
			}
		}

		internal static bool IsVampire(Player player)
		{
			VampireController component = ((Component)player).GetComponent<VampireController>();
			if ((Object)(object)player == (Object)(object)Player.m_localPlayer && (Object)(object)component != (Object)null)
			{
				return component.State.IsVampire;
			}
			ZNetView component2 = ((Component)player).GetComponent<ZNetView>();
			if ((Object)(object)component2 != (Object)null && component2.IsValid())
			{
				return component2.GetZDO().GetBool("com.igentuman.vampirizm.vampire", false);
			}
			return false;
		}

		internal static void SetBatForm(ZNetView view, bool active)
		{
			if (!((Object)(object)view == (Object)null) && view.IsValid() && view.IsOwner())
			{
				ZDO zDO = view.GetZDO();
				if (zDO.GetBool("com.igentuman.vampirizm.batform", false) != active)
				{
					zDO.Set("com.igentuman.vampirizm.batform", active);
				}
			}
		}

		internal static bool IsBatForm(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			VampireController component = ((Component)player).GetComponent<VampireController>();
			if ((Object)(object)player == (Object)(object)Player.m_localPlayer && (Object)(object)component != (Object)null)
			{
				return component.BatForm?.Active ?? false;
			}
			ZNetView component2 = ((Component)player).GetComponent<ZNetView>();
			if ((Object)(object)component2 != (Object)null && component2.IsValid())
			{
				return component2.GetZDO().GetBool("com.igentuman.vampirizm.batform", false);
			}
			return false;
		}
	}
}
namespace Vampirizm.Localization
{
	internal static class VampireLocalization
	{
		internal static void Register()
		{
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				["vampirizm_skill"] = "Vampirism",
				["vampirizm_skill_description"] = "Increases blood capacity, grants eitr and unlocks vampire abilities.",
				["vampirizm_no_player"] = "Enter a world as a player first.",
				["vampirizm_devcommands_required"] = "Enable devcommands first.",
				["vampirizm_admin_required"] = "Requires server admin rights and Debug: Enable commands.",
				["vampirizm_unavailable"] = "Vampirism data is not ready, protected, or the character is dead.",
				["vampirizm_not_vampire"] = "This character is not a vampire.",
				["vampirizm_status"] = "Vampire: blood {0:0.##}/{1:0.##}, skill {2:0.##}.",
				["vampirizm_food_forbidden"] = "A vampire cannot eat or drink this.",
				["vampirizm_blood_full"] = "Your blood is full.",
				["vampirizm_blood_gained"] = "+$1 blood",
				["vampirizm_tooltip_blood"] = "<color=#d03030>Vampire: +$1 blood</color>",
				["vampirizm_tooltip_forbidden"] = "<color=#d03030>Vampires cannot consume this.</color>",
				["vampirizm_sun_warning"] = "The sun burns your skin! Find a roof or cover yourself in slime.",
				["vampirizm_silver_warning"] = "Silver burns your skin! Get rid of it.",
				["vampirizm_good_evening"] = "Good evening. The sun has set.",
				["vampirizm_slime_applied"] = "Slime protects you from the sun.",
				["vampirizm_slime_wet"] = "Slime will not stick to wet skin.",
				["vampirizm_slime_washed"] = "Water washed the slime off.",
				["vampirizm_se_slime"] = "Slime",
				["vampirizm_se_slime_tooltip"] = "Protects a vampire from sunlight. Any wetness washes it off.",
				["vampirizm_tooltip_slime"] = "<color=#d03030>Vampire: sun protection for $1 s</color>",
				["item_vampirizm_rune"] = "Vampire rune",
				["item_vampirizm_rune_description"] = "A stone soaked in leech blood. Use it on a clear night under the open sky to become a vampire. Not consumed if the ritual fails.",
				["vampirizm_rune_already"] = "You are already a vampire.",
				["vampirizm_rune_not_night"] = "The rune answers only at night.",
				["vampirizm_rune_weather"] = "The ritual needs a clear night sky.",
				["vampirizm_rune_sky"] = "The ritual needs the open sky above you.",
				["vampirizm_converted_ritual"] = "The rune drinks your blood. You are a vampire now.",
				["vampirizm_converted_bite"] = "$1 bit you. You are a vampire now.",
				["vampirizm_bite_no_target"] = "Nothing to bite here.",
				["vampirizm_bite_forbidden"] = "This creature has no blood you can drink.",
				["vampirizm_bite_cooldown"] = "Your fangs are not ready yet.",
				["vampirizm_bite_busy"] = "Someone else is already drinking from it.",
				["vampirizm_bite_escaped"] = "Your prey slipped away.",
				["vampirizm_bite_interrupted"] = "The bite was interrupted.",
				["vampirizm_bite_lost"] = "The bite was lost.",
				["vampirizm_bite_victim_died"] = "Your prey is drained.",
				["vampirizm_bite_converted"] = "$1 is a vampire now.",
				["vampirizm_bite_refused"] = "$1 resisted the curse.",
				["vampirizm_bite_already"] = "$1 is already a vampire.",
				["vampirizm_bite_disabled"] = "Conversion by bite is disabled on this server.",
				["vampirizm_bite_failed"] = "The bite did not take hold.",
				["vampirizm_action_dash"] = "Dash",
				["vampirizm_action_invisibility"] = "Invisibility",
				["vampirizm_action_batform"] = "Bat form",
				["vampirizm_control_dash"] = "Vampire: dash",
				["vampirizm_control_invisibility"] = "Vampire: invisibility",
				["vampirizm_control_batform"] = "Vampire: bat form",
				["vampirizm_ability_locked"] = "$1 unlocks at Vampirism level $2.",
				["vampirizm_ability_not_ready"] = "$1: not available in this version yet.",
				["vampirizm_ability_no_blood"] = "Not enough blood.",
				["vampirizm_invisibility_on"] = "You fade from sight.",
				["vampirizm_invisibility_off"] = "You become visible.",
				["vampirizm_dash_cooldown"] = "The dash is not ready yet.",
				["vampirizm_dash_no_room"] = "No room to dash.",
				["vampirizm_dash_busy"] = "You can't dash right now.",
				["vampirizm_batform_on"] = "Blood whirls around you as you become a bat.",
				["vampirizm_batform_off"] = "The bat form dissolves in a burst of blood and shadow.",
				["vampirizm_bat_busy"] = "You can't transform right now."
			});
			text = "Russian";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				["vampirizm_skill"] = "Вампиризм",
				["vampirizm_skill_description"] = "Увеличивает запас крови, даёт эйтр и открывает способности вампира.",
				["vampirizm_no_player"] = "Сначала войдите в мир персонажем.",
				["vampirizm_devcommands_required"] = "Сначала включите devcommands.",
				["vampirizm_admin_required"] = "Нужны права администратора сервера и настройка Debug: Enable commands.",
				["vampirizm_unavailable"] = "Данные вампиризма ещё не загружены, защищены от изменений или персонаж мёртв.",
				["vampirizm_not_vampire"] = "Этот персонаж не вампир.",
				["vampirizm_status"] = "Вампир: кровь {0:0.##}/{1:0.##}, навык {2:0.##}.",
				["vampirizm_food_forbidden"] = "Вампир не может это есть или пить.",
				["vampirizm_blood_full"] = "Запас крови полон.",
				["vampirizm_blood_gained"] = "+$1 крови",
				["vampirizm_tooltip_blood"] = "<color=#d03030>Вампир: +$1 крови</color>",
				["vampirizm_tooltip_forbidden"] = "<color=#d03030>Вампиру это недоступно.</color>",
				["vampirizm_sun_warning"] = "Солнце жжёт кожу! Найдите крышу или нанесите слизь.",
				["vampirizm_silver_warning"] = "Серебро жжёт кожу! Избавьтесь от него.",
				["vampirizm_good_evening"] = "Добрый вечер. Солнце село.",
				["vampirizm_slime_applied"] = "Слизь защищает от солнца.",
				["vampirizm_slime_wet"] = "Слизь не держится на мокрой коже.",
				["vampirizm_slime_washed"] = "Вода смыла слизь.",
				["vampirizm_se_slime"] = "Слизь",
				["vampirizm_se_slime_tooltip"] = "Защищает вампира от солнца. Любое намокание её смывает.",
				["vampirizm_tooltip_slime"] = "<color=#d03030>Вампир: защита от солнца на $1 с</color>",
				["item_vampirizm_rune"] = "Руна вампира",
				["item_vampirizm_rune_description"] = "Камень, пропитанный кровью пиявки. Примените ясной ночью под открытым небом, чтобы стать вампиром. Если ритуал не удался, руна не тратится.",
				["vampirizm_rune_already"] = "Вы уже вампир.",
				["vampirizm_rune_not_night"] = "Руна откликается только ночью.",
				["vampirizm_rune_weather"] = "Для ритуала нужно ясное ночное небо.",
				["vampirizm_rune_sky"] = "Для ритуала над головой должно быть открытое небо.",
				["vampirizm_converted_ritual"] = "Руна пьёт вашу кровь. Теперь вы вампир.",
				["vampirizm_converted_bite"] = "$1 укусил вас. Теперь вы вампир.",
				["vampirizm_bite_no_target"] = "Здесь некого укусить.",
				["vampirizm_bite_forbidden"] = "У этого существа нет пригодной крови.",
				["vampirizm_bite_cooldown"] = "Клыки ещё не готовы.",
				["vampirizm_bite_busy"] = "Из этой жертвы уже кто-то пьёт.",
				["vampirizm_bite_escaped"] = "Жертва вырвалась.",
				["vampirizm_bite_interrupted"] = "Укус прерван.",
				["vampirizm_bite_lost"] = "Укус сорвался.",
				["vampirizm_bite_victim_died"] = "Жертва иссушена.",
				["vampirizm_bite_converted"] = "$1 теперь вампир.",
				["vampirizm_bite_refused"] = "$1 устоял перед проклятием.",
				["vampirizm_bite_already"] = "$1 уже вампир.",
				["vampirizm_bite_disabled"] = "Обращение укусом отключено на этом сервере.",
				["vampirizm_bite_failed"] = "Укус не подействовал.",
				["vampirizm_action_dash"] = "Рывок",
				["vampirizm_action_invisibility"] = "Невидимость",
				["vampirizm_action_batform"] = "Превращение в летучую мышь",
				["vampirizm_control_dash"] = "Вампир: рывок",
				["vampirizm_control_invisibility"] = "Вампир: невидимость",
				["vampirizm_control_batform"] = "Вампир: летучая мышь",
				["vampirizm_ability_locked"] = "$1: откроется на уровне вампиризма $2.",
				["vampirizm_ability_not_ready"] = "$1: пока недоступно в этой версии.",
				["vampirizm_ability_no_blood"] = "Недостаточно крови.",
				["vampirizm_invisibility_on"] = "Вы исчезаете из виду.",
				["vampirizm_invisibility_off"] = "Вы снова видимы.",
				["vampirizm_dash_cooldown"] = "Рывок ещё не готов.",
				["vampirizm_dash_no_room"] = "Для рывка нет места.",
				["vampirizm_dash_busy"] = "Сейчас нельзя сделать рывок.",
				["vampirizm_batform_on"] = "Кровь вихрем обвивает вас — вы превращаетесь в летучую мышь.",
				["vampirizm_batform_off"] = "Облик мыши рассыпается всплеском крови и теней.",
				["vampirizm_bat_busy"] = "Сейчас нельзя превратиться."
			});
		}
	}
}
namespace Vampirizm.Items
{
	internal static class VampireRune
	{
		internal const string PrefabName = "VampirizmRune";

		private const string IconResource = "Vampirizm.Assets.vampire_rune.png";

		private static readonly Color Tint = new Color(0.35f, 0.05f, 0.07f, 1f);

		private static readonly Color Glow = new Color(0.9f, 0.05f, 0.08f, 1f);

		internal static void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable += AddItem;
		}

		internal static bool IsRune(ItemData item)
		{
			if ((Object)(object)item?.m_dropPrefab != (Object)null)
			{
				return ((Object)item.m_dropPrefab).name == "VampirizmRune";
			}
			return false;
		}

		private static void AddItem()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= AddItem;
			ItemConfig val = new ItemConfig();
			val.Name = "$item_vampirizm_rune";
			val.Description = "$item_vampirizm_rune_description";
			val.CraftingStation = CraftingStations.Workbench;
			val.Weight = 1f;
			val.StackSize = 10;
			val.Icons = (Sprite[])(object)new Sprite[1] { LoadIcon() };
			val.Requirements = (RequirementConfig[])(object)new RequirementConfig[3]
			{
				new RequirementConfig("TrophyLeech", 1, 0, true),
				new RequirementConfig("Stone", 1, 0, true),
				new RequirementConfig("Ruby", 2, 0, true)
			};
			ItemConfig val2 = val;
			CustomItem val3 = new CustomItem("VampirizmRune", "Stone", val2);
			ApplyTint(val3.ItemPrefab);
			ItemManager.Instance.AddItem(val3);
		}

		private static Sprite LoadIcon()
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			using Stream stream = typeof(VampireRune).Assembly.GetManifestResourceStream("Vampirizm.Assets.vampire_rune.png");
			using MemoryStream memoryStream = new MemoryStream();
			if (stream == null)
			{
				Plugin.Warn("Vampire rune icon resource is missing.");
				return null;
			}
			stream.CopyTo(memoryStream);
			Texture2D val = AssetUtils.LoadImage(memoryStream.ToArray());
			((Object)val).name = "vampire_rune";
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
		}

		private static void ApplyTint(GameObject prefab)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				Material[] sharedMaterials = val.sharedMaterials;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					if (!((Object)(object)sharedMaterials[j] == (Object)null))
					{
						Material val2 = new Material(sharedMaterials[j]);
						if (val2.HasProperty("_Color"))
						{
							val2.color = Tint;
						}
						if (val2.HasProperty("_EmissionColor"))
						{
							val2.EnableKeyword("_EMISSION");
							val2.SetColor("_EmissionColor", Glow * 0.6f);
						}
						sharedMaterials[j] = val2;
					}
				}
				val.sharedMaterials = sharedMaterials;
			}
		}
	}
}
namespace Vampirizm.Feeding
{
	internal static class BloodFeeding
	{
		internal static bool TryDrink(Player player, Inventory inventory, ItemData item)
		{
			//IL_00c9: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			if (!BloodItemRegistry.TryGetBlood(item, out var blood))
			{
				return false;
			}
			VampireController component = ((Component)player).GetComponent<VampireController>();
			if ((Object)(object)component == (Object)null || !component.IsActiveVampire)
			{
				return false;
			}
			if (!component.CanChange)
			{
				((Character)player).Message((MessageType)2, "$vampirizm_unavailable", 0, (Sprite)null, false);
				return true;
			}
			if (BloodRules.IsFull(component.State.Blood, component.Capacity))
			{
				((Character)player).Message((MessageType)2, "$vampirizm_blood_full", 0, (Sprite)null, false);
				return true;
			}
			if (!VampireFood.CanDrink(player, item))
			{
				return true;
			}
			if (!inventory.RemoveOneItem(item))
			{
				return true;
			}
			VampireFood.Fill(player, item);
			float acceptedBlood = component.AddBlood(blood);
			float num = DrainRules.Experience(acceptedBlood, Plugin.Instance.Settings.XpPerItemBlood.Value, victimAllowsXp: true);
			if (num > 0f)
			{
				((Character)player).RaiseSkill(VampirismSkill.Type, num);
			}
			((Humanoid)player).m_consumeItemEffects.Create(((Component)player).transform.position, Quaternion.identity, (Transform)null, 1f, -1, ((Character)player).GetZDOID());
			((Character)player).GetZAnim().SetTrigger("eat");
			((Character)player).Message((MessageType)2, Localization.instance.Localize("$vampirizm_blood_gained", new string[1] { acceptedBlood.ToString("0.#", CultureInfo.InvariantCulture) }), 0, (Sprite)null, false);
			return true;
		}

		internal static string Tooltip(ItemData item)
		{
			VampireController local = VampireController.Local;
			if ((Object)(object)local == (Object)null || !local.IsActiveVampire)
			{
				return null;
			}
			if (BloodItemRegistry.TryGetBlood(item, out var blood))
			{
				return Localization.instance.Localize("$vampirizm_tooltip_blood", new string[1] { blood.ToString("0.#", CultureInfo.InvariantCulture) });
			}
			if (SlimeProtection.IsSlimeItem(item))
			{
				return Localization.instance.Localize("$vampirizm_tooltip_slime", new string[1] { Plugin.Instance.Settings.SlimeDuration.Value.ToString("0", CultureInfo.InvariantCulture) });
			}
			if (!BloodItemRegistry.IsForbiddenConsumable(item))
			{
				return null;
			}
			return Localization.instance.Localize("$vampirizm_tooltip_forbidden");
		}
	}
	internal static class BloodItemRegistry
	{
		private static ConfigEntry<string> _source;

		private static ConfigEntry<bool> _allowMeads;

		private static Dictionary<string, float> _table = new Dictionary<string, float>();

		internal static void Initialize(ConfigEntry<string> source, ConfigEntry<bool> allowMeads)
		{
			_source = source;
			_allowMeads = allowMeads;
			_source.SettingChanged += delegate
			{
				Rebuild();
			};
			Rebuild();
		}

		private static void Rebuild()
		{
			List<string> list = new List<string>();
			_table = BloodItemTable.Parse(_source.Value, list);
			if (list.Count > 0)
			{
				Plugin.Warn("Blood items: ignored or overridden entries: " + string.Join(", ", list));
			}
		}

		internal static string PrefabId(ItemData item)
		{
			if (!((Object)(object)item?.m_dropPrefab != (Object)null))
			{
				return null;
			}
			return ((Object)item.m_dropPrefab).name;
		}

		internal static bool TryGetBlood(ItemData item, out float blood)
		{
			blood = 0f;
			string text = PrefabId(item);
			if (text != null)
			{
				return _table.TryGetValue(text, out blood);
			}
			return false;
		}

		internal static bool IsBloodItem(ItemData item)
		{
			float blood;
			return TryGetBlood(item, out blood);
		}

		internal static bool IsBloodId(string id)
		{
			if (id != null)
			{
				return _table.ContainsKey(id);
			}
			return false;
		}

		internal static bool IsForbiddenConsumable(ItemData item)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			if (item == null || (int)item.m_shared.m_itemType != 2)
			{
				return false;
			}
			if (IsBloodItem(item))
			{
				return false;
			}
			SharedData shared = item.m_shared;
			if (shared.m_food > 0f || shared.m_foodStamina > 0f || shared.m_foodEitr > 0f)
			{
				return true;
			}
			if ((Object)(object)shared.m_consumeStatusEffect != (Object)null)
			{
				ConfigEntry<bool> allowMeads = _allowMeads;
				if (allowMeads == null)
				{
					return true;
				}
				return !allowMeads.Value;
			}
			return false;
		}
	}
	public static class BloodItemTable
	{
		public const float MaxAmount = 10000f;

		private static readonly char[] EntrySeparators = new char[4] { ',', ';', '\n', '\r' };

		public static Dictionary<string, float> Parse(string raw)
		{
			return Parse(raw, new List<string>());
		}

		public static Dictionary<string, float> Parse(string raw, List<string> errors)
		{
			Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.Ordinal);
			if (string.IsNullOrEmpty(raw))
			{
				return dictionary;
			}
			string[] array = raw.Split(EntrySeparators, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length == 0)
				{
					continue;
				}
				int num = text.IndexOf(':');
				string text2 = ((num > 0) ? text.Substring(0, num).Trim() : "");
				string s = ((num > 0) ? text.Substring(num + 1).Trim() : "");
				if (text2.Length == 0 || text2.IndexOf(' ') >= 0 || !float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !BloodRules.IsFinite(result) || result <= 0f)
				{
					errors.Add(text);
					continue;
				}
				if (dictionary.ContainsKey(text2))
				{
					errors.Add(text);
				}
				dictionary[text2] =