Decompiled source of Quads Skal Tavern v0.5.0

plugins/SkalTavern.dll

Decompiled 3 hours 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 System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using DHack.Shared;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityEngine.PostProcessing;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially or fully created with the assistance of Generative AI (Claude Code).")]
[assembly: AssemblyMetadata("AI_Model_Vendor", "Anthropic")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SkalTavern
{
	[HarmonyPatch(typeof(Player), "SetControls")]
	internal static class Player_SetControls_Drunk
	{
		private static Vector3 _smooth;

		private static float _flipUntil;

		private static float _nextFlip;

		private static bool Prepare()
		{
			return AccessTools.Method(typeof(Player), "SetControls", (Type[])null, (Type[])null) != null;
		}

		private static void Prefix(Player __instance, ref Vector3 movedir)
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: 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)
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			float level = Tipsy.Level;
			if (level < 8f)
			{
				_smooth = movedir;
				return;
			}
			float strength = Fx.Strength;
			float time = Time.time;
			float num = Fx.F(20f, 100f) * strength * Plugin.Drift.Value / 100f;
			_smooth = Vector3.Lerp(_smooth, movedir, 1f - Mathf.Exp((0f - Time.deltaTime) * Mathf.Lerp(24f, 2.6f, Mathf.Clamp01(num))));
			if (num > 0.02f)
			{
				movedir = _smooth;
			}
			if (((Vector3)(ref movedir)).sqrMagnitude < 0.0004f)
			{
				return;
			}
			float num2 = Fx.F(22f, 100f) * strength * Plugin.Drift.Value / 100f;
			float num3 = (Mathf.Sin(time * 0.8f) + 0.5f * Mathf.Sin(time * 1.9f + 0.7f)) * 30f * num2;
			movedir = Quaternion.Euler(0f, num3, 0f) * movedir;
			if (Plugin.ConfusionOn.Value && level >= 85f)
			{
				if (_nextFlip == 0f)
				{
					_nextFlip = time + Random.Range(8f, 16f);
				}
				if (time >= _nextFlip)
				{
					_nextFlip = time + Random.Range(16f, 32f);
					_flipUntil = time + 1.3f;
					((Character)__instance).Message((MessageType)1, Translations.T("skaltavern_room_spins"), 0, (Sprite)null, false);
				}
				if (time < _flipUntil)
				{
					movedir = -movedir;
				}
			}
			else
			{
				_nextFlip = 0f;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "SetMouseLook")]
	internal static class Player_SetMouseLook_Drunk
	{
		private static Vector2 _look;

		private static bool Prepare()
		{
			return AccessTools.Method(typeof(Player), "SetMouseLook", (Type[])null, (Type[])null) != null;
		}

		private static void Prefix(Player __instance, ref Vector2 mouseLook)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				float num = Fx.F(25f, 100f) * Fx.Strength * Plugin.Drift.Value / 100f;
				if (num <= 0.01f)
				{
					_look = mouseLook;
					return;
				}
				_look = Vector2.Lerp(_look, mouseLook, Mathf.Lerp(1f, 0.16f, Mathf.Clamp01(num)));
				float time = Time.time;
				mouseLook = _look + new Vector2(Mathf.Sin(time * 0.9f), Mathf.Sin(time * 0.6f + 1f) * 0.6f) * 0.05f * num;
			}
		}
	}
	[HarmonyPatch(typeof(Chat), "SendText")]
	internal static class Chat_SendText_Slur
	{
		private static bool Prepare()
		{
			return AccessTools.Method(typeof(Chat), "SendText", (Type[])null, (Type[])null) != null;
		}

		private static void Prefix(ref string text)
		{
			if (Plugin.SlurOn.Value && !string.IsNullOrEmpty(text) && !text.StartsWith("/") && !(Tipsy.Level < 30f))
			{
				text = Slur(text, Fx.F(30f, 100f));
			}
		}

		private static string Slur(string text, float k)
		{
			StringBuilder stringBuilder = new StringBuilder();
			string[] array = text.Split(new char[1] { ' ' });
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i];
				if (Random.value < 0.25f + 0.55f * k)
				{
					text2 = text2.Replace("s", "sh").Replace("S", "Sh").Replace("th", "d")
						.Replace("r", "rr");
					if (Random.value < 0.35f * k && text2.Length > 2)
					{
						text2 = text2 + text2.Substring(text2.Length - 1, 1) + text2.Substring(text2.Length - 1, 1);
					}
				}
				stringBuilder.Append(text2);
				if (Random.value < 0.12f + 0.2f * k)
				{
					stringBuilder.Append(" *hic*");
				}
				if (i < array.Length - 1)
				{
					stringBuilder.Append(' ');
				}
			}
			return stringBuilder.ToString();
		}
	}
	internal static class Drinks
	{
		internal class Def
		{
			public string Prefab;

			public string Display;

			public string Flavour;

			public float Amount;

			public Color Liquid;

			public int Makes;

			public (string Item, int Count)[] Cost;
		}

		internal static readonly Def[] All = new Def[4]
		{
			new Def
			{
				Prefab = "dh_drink_ale",
				Display = "$skaltavern_ale",
				Amount = 14f,
				Liquid = new Color(0.89f, 0.74f, 0.3f),
				Makes = 2,
				Flavour = "$skaltavern_ale_desc",
				Cost = new(string, int)[2]
				{
					("Barley", 3),
					("Honey", 1)
				}
			},
			new Def
			{
				Prefab = "dh_drink_honeymead",
				Display = "$skaltavern_honeymead",
				Amount = 22f,
				Liquid = new Color(0.95f, 0.58f, 0.1f),
				Makes = 2,
				Flavour = "$skaltavern_honeymead_desc",
				Cost = new(string, int)[2]
				{
					("Honey", 4),
					("Raspberry", 2)
				}
			},
			new Def
			{
				Prefab = "dh_drink_wine",
				Display = "$skaltavern_wine",
				Amount = 20f,
				Liquid = new Color(0.4f, 0.1f, 0.34f),
				Makes = 2,
				Flavour = "$skaltavern_wine_desc",
				Cost = new(string, int)[2]
				{
					("Blueberries", 4),
					("Honey", 1)
				}
			},
			new Def
			{
				Prefab = "dh_drink_skaldmead",
				Display = "$skaltavern_skaldmead",
				Amount = 34f,
				Liquid = new Color(0.97f, 0.8f, 0.2f),
				Makes = 2,
				Flavour = "$skaltavern_skaldmead_desc",
				Cost = new(string, int)[2]
				{
					("Honey", 5),
					("Cloudberry", 3)
				}
			}
		};

		internal static readonly int TipsyHash = StringExtensionMethods.GetStableHashCode("SE_SkalTipsy");

		internal static readonly int HangoverHash = StringExtensionMethods.GetStableHashCode("SE_SkalHangover");

		internal static readonly int SkalHash = StringExtensionMethods.GetStableHashCode("SE_SkalBuff");

		private static GameObject _holder;

		private static bool _items;

		private static bool _recipes;

		private static readonly Dictionary<string, GameObject> Made = new Dictionary<string, GameObject>();

		private static readonly List<GameObject> ItemPrefabs = new List<GameObject>();

		private static readonly List<StatusEffect> Effects = new List<StatusEffect>();

		private static readonly List<Recipe> Recipes = new List<Recipe>();

		private static Sprite _mug;

		private static bool _rebound;

		private static GameObject Find(string name)
		{
			if (Made.TryGetValue(name, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(name) : null);
			if ((Object)(object)val == (Object)null && (Object)(object)ObjectDB.instance != (Object)null)
			{
				val = ObjectDB.instance.GetItemPrefab(name);
			}
			return val;
		}

		private static Dictionary<int, GameObject> Named(ZNetScene scene)
		{
			return (Dictionary<int, GameObject>)AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs").GetValue(scene);
		}

		internal static void Register()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			ObjectDB instance = ObjectDB.instance;
			ZNetScene instance2 = ZNetScene.instance;
			if ((Object)(object)instance == (Object)null && (Object)(object)instance2 == (Object)null)
			{
				return;
			}
			if ((Object)(object)_holder == (Object)null)
			{
				_holder = new GameObject("SkalTavernPrefabs");
				_holder.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)_holder);
			}
			if (!_items)
			{
				if (!BuildItems())
				{
					return;
				}
				_items = true;
			}
			if ((Object)(object)instance2 != (Object)null)
			{
				Dictionary<int, GameObject> dictionary = Named(instance2);
				foreach (GameObject value in Made.Values)
				{
					if (!instance2.m_prefabs.Contains(value))
					{
						instance2.m_prefabs.Add(value);
					}
					dictionary[StringExtensionMethods.GetStableHashCode(((Object)value).name)] = value;
				}
			}
			if ((Object)(object)instance != (Object)null)
			{
				if (!_recipes)
				{
					GameObject obj = Find("piece_cauldron");
					CraftingStation val = ((obj != null) ? obj.GetComponent<CraftingStation>() : null);
					if ((Object)(object)val != (Object)null)
					{
						BuildRecipes(val);
						_recipes = true;
					}
				}
				bool flag = false;
				foreach (GameObject item in ItemPrefabs)
				{
					if (!instance.m_items.Contains(item))
					{
						instance.m_items.RemoveAll((GameObject i) => (Object)(object)i == (Object)null || ((Object)i).name == ((Object)item).name);
						instance.m_items.Add(item);
						flag = true;
					}
				}
				foreach (StatusEffect effect in Effects)
				{
					if (!instance.m_StatusEffects.Contains(effect))
					{
						instance.m_StatusEffects.RemoveAll((StatusEffect e) => (Object)(object)e == (Object)null || ((Object)e).name == ((Object)effect).name);
						instance.m_StatusEffects.Add(effect);
						flag = true;
					}
				}
				foreach (Recipe recipe in Recipes)
				{
					if (!instance.m_recipes.Contains(recipe))
					{
						instance.m_recipes.RemoveAll((Recipe r) => (Object)(object)r == (Object)null || ((Object)r).name == ((Object)recipe).name);
						instance.m_recipes.Add(recipe);
					}
				}
				if (flag)
				{
					AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null).Invoke(instance, null);
				}
			}
			if (!_rebound)
			{
				Rebind();
			}
		}

		private static void Rebind()
		{
			if ((Object)(object)ObjectDB.instance == (Object)null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			_rebound = true;
			int num = 0;
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				num += Rebind(((Humanoid)allPlayer).GetInventory());
			}
			Container[] array = Object.FindObjectsOfType<Container>();
			foreach (Container val in array)
			{
				if ((Object)(object)val != (Object)null)
				{
					num += Rebind(val.GetInventory());
				}
			}
			ItemDrop[] array2 = Object.FindObjectsOfType<ItemDrop>();
			foreach (ItemDrop val2 in array2)
			{
				if ((Object)(object)val2 != (Object)null && Fix(val2.m_itemData))
				{
					num++;
				}
			}
			if (num > 0)
			{
				Plugin.Log.LogInfo((object)$"{num} drink(s) already in the world were attached to the reloaded mod");
			}
		}

		private static int Rebind(Inventory inventory)
		{
			if (inventory != null)
			{
				return inventory.GetAllItems().Count(Fix);
			}
			return 0;
		}

		private static bool Fix(ItemData item)
		{
			if (item?.m_shared == null)
			{
				return false;
			}
			Def def = All.FirstOrDefault((Def x) => x.Display == item.m_shared.m_name);
			if (def == null || !Made.TryGetValue(def.Prefab, out var value) || (Object)(object)value == (Object)null || (Object)(object)item.m_dropPrefab == (Object)(object)value)
			{
				return false;
			}
			item.m_shared = value.GetComponent<ItemDrop>().m_itemData.m_shared;
			item.m_dropPrefab = value;
			return true;
		}

		internal static void Unregister()
		{
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance != (Object)null)
			{
				Dictionary<int, GameObject> dictionary = Named(instance);
				foreach (GameObject value2 in Made.Values)
				{
					instance.m_prefabs.Remove(value2);
					int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)value2).name);
					if (dictionary.TryGetValue(stableHashCode, out var value) && (Object)(object)value == (Object)(object)value2)
					{
						dictionary.Remove(stableHashCode);
					}
				}
			}
			ObjectDB instance2 = ObjectDB.instance;
			if ((Object)(object)instance2 != (Object)null)
			{
				instance2.m_items.RemoveAll((GameObject i) => (Object)(object)i == (Object)null || ItemPrefabs.Contains(i));
				instance2.m_StatusEffects.RemoveAll((StatusEffect e) => (Object)(object)e == (Object)null || Effects.Contains(e));
				instance2.m_recipes.RemoveAll((Recipe r) => (Object)(object)r == (Object)null || Recipes.Contains(r));
				AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null).Invoke(instance2, null);
			}
			foreach (Recipe recipe in Recipes)
			{
				Object.Destroy((Object)(object)recipe);
			}
			foreach (StatusEffect effect in Effects)
			{
				Object.Destroy((Object)(object)effect);
			}
			Made.Clear();
			ItemPrefabs.Clear();
			Effects.Clear();
			Recipes.Clear();
			_items = (_recipes = (_rebound = false));
			if ((Object)(object)_holder != (Object)null)
			{
				Object.Destroy((Object)(object)_holder);
			}
			_holder = null;
		}

		private static bool BuildItems()
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Find("Tankard");
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			_mug = val.GetComponent<ItemDrop>().m_itemData.m_shared.m_icons?.FirstOrDefault();
			Def[] all = All;
			foreach (Def def in all)
			{
				Sprite icon = Tint(_mug, def.Liquid);
				SE_Drink sE_Drink = ScriptableObject.CreateInstance<SE_Drink>();
				((Object)sE_Drink).name = "SE_" + def.Prefab;
				((StatusEffect)sE_Drink).m_name = def.Display;
				((StatusEffect)sE_Drink).m_icon = icon;
				((StatusEffect)sE_Drink).m_ttl = 1f;
				sE_Drink.Amount = def.Amount / 4f;
				sE_Drink.Share = 0.25f;
				Effects.Add((StatusEffect)(object)sE_Drink);
				MakeItem(val, def, icon, (StatusEffect)(object)sE_Drink);
			}
			SE_Tipsy sE_Tipsy = ScriptableObject.CreateInstance<SE_Tipsy>();
			((Object)sE_Tipsy).name = "SE_SkalTipsy";
			((StatusEffect)sE_Tipsy).m_name = "$skaltavern_tipsy";
			((StatusEffect)sE_Tipsy).m_icon = Tint(_mug, new Color(0.9f, 0.6f, 0.2f));
			SE_Hangover sE_Hangover = ScriptableObject.CreateInstance<SE_Hangover>();
			((Object)sE_Hangover).name = "SE_SkalHangover";
			((StatusEffect)sE_Hangover).m_name = "$skaltavern_hangover";
			((StatusEffect)sE_Hangover).m_icon = Tint(_mug, new Color(0.45f, 0.5f, 0.4f));
			SE_Skal sE_Skal = ScriptableObject.CreateInstance<SE_Skal>();
			((Object)sE_Skal).name = "SE_SkalBuff";
			((StatusEffect)sE_Skal).m_name = "$skaltavern_skal";
			((StatusEffect)sE_Skal).m_icon = Tint(_mug, new Color(1f, 0.85f, 0.3f));
			Effects.Add((StatusEffect)(object)sE_Tipsy);
			Effects.Add((StatusEffect)(object)sE_Hangover);
			Effects.Add((StatusEffect)(object)sE_Skal);
			return true;
		}

		private static void MakeItem(GameObject source, Def d, Sprite icon, StatusEffect effect)
		{
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			GameObject val = Object.Instantiate<GameObject>(source, _holder.transform);
			((Object)val).name = d.Prefab;
			Renderer[] componentsInChildren = val.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				Material[] sharedMaterials = val2.sharedMaterials;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					if ((Object)(object)sharedMaterials[j] != (Object)null && ((Object)sharedMaterials[j]).name.StartsWith("mead"))
					{
						sharedMaterials[j] = new Material(sharedMaterials[j])
						{
							color = d.Liquid
						};
					}
				}
				val2.sharedMaterials = sharedMaterials;
			}
			ItemDrop component = val.GetComponent<ItemDrop>();
			SharedData shared = component.m_itemData.m_shared;
			shared.m_name = d.Display;
			shared.m_description = d.Flavour + "\n\n$skaltavern_drink_note\n$skaltavern_swig_note";
			shared.m_itemType = (ItemType)2;
			shared.m_icons = (Sprite[])(object)new Sprite[1] { icon };
			shared.m_maxStackSize = 10;
			shared.m_weight = 0.5f;
			shared.m_value = 0;
			shared.m_maxQuality = 1;
			shared.m_variants = 0;
			shared.m_food = 0f;
			shared.m_foodStamina = 0f;
			shared.m_foodEitr = 0f;
			shared.m_foodBurnTime = 0f;
			shared.m_foodEatAnimTime = 1.8f;
			shared.m_teleportable = true;
			shared.m_questItem = false;
			shared.m_dlc = "";
			shared.m_equipStatusEffect = null;
			shared.m_consumeStatusEffect = effect;
			component.m_itemData.m_dropPrefab = val;
			component.m_itemData.m_stack = 1;
			Made[d.Prefab] = val;
			ItemPrefabs.Add(val);
		}

		private static void BuildRecipes(CraftingStation cauldron)
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Expected O, but got Unknown
			Def[] all = All;
			foreach (Def def in all)
			{
				List<Requirement> list = new List<Requirement>();
				(string, int)[] cost = def.Cost;
				for (int j = 0; j < cost.Length; j++)
				{
					(string, int) tuple = cost[j];
					string item = tuple.Item1;
					int item2 = tuple.Item2;
					GameObject obj = Find(item);
					ItemDrop val = ((obj != null) ? obj.GetComponent<ItemDrop>() : null);
					if ((Object)(object)val == (Object)null)
					{
						Plugin.Log.LogWarning((object)(def.Display + ": the item " + item + " was not found, so it has no recipe"));
						list.Clear();
						break;
					}
					list.Add(new Requirement
					{
						m_resItem = val,
						m_amount = item2,
						m_recover = false
					});
				}
				if (list.Count != 0)
				{
					Recipe val2 = ScriptableObject.CreateInstance<Recipe>();
					((Object)val2).name = "Recipe_" + def.Prefab;
					val2.m_item = Made[def.Prefab].GetComponent<ItemDrop>();
					val2.m_amount = def.Makes;
					val2.m_craftingStation = cauldron;
					val2.m_minStationLevel = 1;
					val2.m_resources = list.ToArray();
					Recipes.Add(val2);
				}
			}
		}

		private static Sprite Tint(Sprite src, Color liquid)
		{
			//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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: 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_0111: 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)
			if ((Object)(object)src == (Object)null)
			{
				return null;
			}
			try
			{
				Texture2D texture = src.texture;
				Rect textureRect = src.textureRect;
				int num = (int)((Rect)(ref textureRect)).width;
				int num2 = (int)((Rect)(ref textureRect)).height;
				RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)0);
				Graphics.Blit((Texture)(object)texture, temporary);
				RenderTexture active = RenderTexture.active;
				RenderTexture.active = temporary;
				Texture2D val = new Texture2D(num, num2, (TextureFormat)4, false);
				val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0);
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
				float num3 = default(float);
				float num4 = default(float);
				float num5 = default(float);
				Color.RGBToHSV(liquid, ref num3, ref num4, ref num5);
				Color[] pixels = val.GetPixels();
				float num6 = default(float);
				float num7 = default(float);
				float num8 = default(float);
				for (int i = 0; i < pixels.Length; i++)
				{
					Color.RGBToHSV(pixels[i], ref num6, ref num7, ref num8);
					if (num7 > 0.35f && num6 > 0.07f && num6 < 0.18f)
					{
						Color val2 = Color.HSVToRGB(num3, Mathf.Clamp01(Mathf.Max(num7, num4 * 0.9f)), num8);
						val2.a = pixels[i].a;
						pixels[i] = val2;
					}
				}
				val.SetPixels(pixels);
				val.Apply();
				return Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num2), new Vector2(0.5f, 0.5f), src.pixelsPerUnit);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not colour a drink's icon: " + ex.Message));
				return src;
			}
		}
	}
	internal static class Fx
	{
		private static float _lastFovSet = -1f;

		private static float _lastFovOffset;

		public static float Kick;

		public static float Strength => Plugin.Strength.Value / 100f;

		public static float F(float from, float to)
		{
			return Mathf.Clamp01((Tipsy.Level - from) / (to - from));
		}

		public static void Camera(GameCamera cam)
		{
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			float level = Tipsy.Level;
			if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)cam == (Object)null))
			{
				float strength = Strength;
				float num = F(12f, 100f) * Plugin.Sway.Value / 100f * strength;
				float time = Time.time;
				if (num > 0f || Mathf.Abs(Kick) > 0.01f)
				{
					((Component)cam).transform.Rotate(new Vector3(Mathf.Sin(time * 0.53f) * 3.2f * num + Kick * 4f, Mathf.Sin(time * 0.37f + 1.3f) * 5.5f * num, Mathf.Sin(time * 0.71f) * 7.5f * num), (Space)1);
					Kick = Mathf.MoveTowards(Kick, 0f, Time.deltaTime * 3f);
				}
				Camera component = ((Component)cam).GetComponent<Camera>();
				if ((Object)(object)component != (Object)null)
				{
					float num2 = F(30f, 100f) * strength * (Mathf.Sin(time * 0.9f) * 6f + Mathf.Sin(time * 2.3f) * 2f) * Plugin.Sway.Value / 100f;
					float fieldOfView = component.fieldOfView;
					float num3 = (Mathf.Approximately(fieldOfView, _lastFovSet) ? (fieldOfView - _lastFovOffset) : fieldOfView);
					component.fieldOfView = num3 + num2;
					_lastFovSet = component.fieldOfView;
					_lastFovOffset = num2;
				}
				if (Plugin.ScreenFx.Value)
				{
					Screen.Apply(cam, level, strength);
				}
				else
				{
					Screen.Restore();
				}
			}
		}

		public static void Reset()
		{
			Screen.Restore();
			Body.Reset();
			Sound.Reset();
			Kick = 0f;
		}
	}
	internal static class Screen
	{
		private class Saved
		{
			public PostProcessingProfile Profile;

			public Settings Vignette;

			public bool VignetteOn;

			public Settings Chroma;

			public bool ChromaOn;

			public Settings Blur;

			public bool BlurOn;

			public Settings Ghost;

			public bool GhostOn;

			public Settings Colour;

			public bool ColourOn;
		}

		private static Saved _saved;

		private static bool _held;

		public static void Apply(GameCamera cam, float level, float s)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: 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_013e: 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_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: 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_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: 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_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_030d: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Unknown result type (might be due to invalid IL or missing references)
			//IL_033d: Unknown result type (might be due to invalid IL or missing references)
			//IL_035b: Unknown result type (might be due to invalid IL or missing references)
			if (level <= 0f)
			{
				Restore();
				return;
			}
			PostProcessingProfile val = ((Component)cam).GetComponent<PostProcessingBehaviour>()?.profile;
			if (!((Object)(object)val == (Object)null))
			{
				if (_saved == null || (Object)(object)_saved.Profile != (Object)(object)val)
				{
					Restore();
					_saved = Take(val);
				}
				_held = true;
				float time = Time.time;
				float num = Fx.F(10f, 100f) * s;
				Settings vignette = _saved.Vignette;
				vignette.intensity = Mathf.Clamp01(Mathf.Max(vignette.intensity, 0.18f + 0.5f * num + 0.07f * Mathf.Sin(time * 1.3f) * num));
				vignette.smoothness = Mathf.Max(vignette.smoothness, 0.55f);
				val.vignette.settings = vignette;
				((PostProcessingModel)val.vignette).enabled = num > 0.01f || _saved.VignetteOn;
				float num2 = Fx.F(22f, 100f) * s;
				Settings chroma = _saved.Chroma;
				chroma.intensity = Mathf.Clamp01(Mathf.Max(chroma.intensity, 0.9f * num2));
				val.chromaticAberration.settings = chroma;
				((PostProcessingModel)val.chromaticAberration).enabled = num2 > 0.01f || _saved.ChromaOn;
				float num3 = Fx.F(38f, 100f) * s;
				Settings blur = _saved.Blur;
				blur.focusDistance = Mathf.Lerp(blur.focusDistance, 3.5f, Mathf.Clamp01(num3 * 1.2f));
				blur.aperture = Mathf.Lerp(blur.aperture, 2.4f, Mathf.Clamp01(num3));
				blur.focalLength = Mathf.Max(blur.focalLength, 50f);
				blur.useCameraFov = false;
				val.depthOfField.settings = blur;
				((PostProcessingModel)val.depthOfField).enabled = num3 > 0.02f || _saved.BlurOn;
				float num4 = Fx.F(42f, 100f) * s;
				Settings ghost = _saved.Ghost;
				ghost.frameBlending = Mathf.Clamp01(Mathf.Max(ghost.frameBlending, 0.85f * num4));
				ghost.shutterAngle = Mathf.Max(ghost.shutterAngle, 200f * num4);
				ghost.sampleCount = Mathf.Max(ghost.sampleCount, 8);
				val.motionBlur.settings = ghost;
				((PostProcessingModel)val.motionBlur).enabled = num4 > 0.02f || _saved.GhostOn;
				float num5 = Fx.F(25f, 100f) * s;
				float num6 = Fx.F(62f, 100f) * s;
				Settings colour = _saved.Colour;
				colour.basic.saturation = colour.basic.saturation + 0.45f * num5;
				colour.basic.hueShift = colour.basic.hueShift + 40f * num6 * Mathf.Sin(time * 0.45f);
				colour.basic.contrast = colour.basic.contrast + 0.12f * num5;
				val.colorGrading.settings = colour;
			}
		}

		private static Saved Take(PostProcessingProfile p)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			return new Saved
			{
				Profile = p,
				Vignette = p.vignette.settings,
				VignetteOn = ((PostProcessingModel)p.vignette).enabled,
				Chroma = p.chromaticAberration.settings,
				ChromaOn = ((PostProcessingModel)p.chromaticAberration).enabled,
				Blur = p.depthOfField.settings,
				BlurOn = ((PostProcessingModel)p.depthOfField).enabled,
				Ghost = p.motionBlur.settings,
				GhostOn = ((PostProcessingModel)p.motionBlur).enabled,
				Colour = p.colorGrading.settings,
				ColourOn = ((PostProcessingModel)p.colorGrading).enabled
			};
		}

		public static void Restore()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			if (_saved != null && _held && (Object)(object)_saved.Profile != (Object)null)
			{
				PostProcessingProfile profile = _saved.Profile;
				profile.vignette.settings = _saved.Vignette;
				((PostProcessingModel)profile.vignette).enabled = _saved.VignetteOn;
				profile.chromaticAberration.settings = _saved.Chroma;
				((PostProcessingModel)profile.chromaticAberration).enabled = _saved.ChromaOn;
				profile.depthOfField.settings = _saved.Blur;
				((PostProcessingModel)profile.depthOfField).enabled = _saved.BlurOn;
				profile.motionBlur.settings = _saved.Ghost;
				((PostProcessingModel)profile.motionBlur).enabled = _saved.GhostOn;
				profile.colorGrading.settings = _saved.Colour;
				((PostProcessingModel)profile.colorGrading).enabled = _saved.ColourOn;
			}
			_held = false;
			_saved = null;
		}
	}
	internal static class Sound
	{
		private static AudioLowPassFilter _low;

		private static AudioChorusFilter _chorus;

		public static void Tick(float level)
		{
			float num = (Plugin.Muffle.Value ? (Fx.F(22f, 100f) * Fx.Strength) : 0f);
			if (num <= 0.01f)
			{
				Reset();
				return;
			}
			if ((Object)(object)_low == (Object)null)
			{
				AudioListener val = Object.FindObjectOfType<AudioListener>();
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				_low = ((Component)val).gameObject.AddComponent<AudioLowPassFilter>();
				_chorus = ((Component)val).gameObject.AddComponent<AudioChorusFilter>();
				_chorus.dryMix = 0.7f;
				_chorus.wetMix1 = 0.4f;
				_chorus.wetMix2 = 0f;
				_chorus.wetMix3 = 0f;
				_chorus.delay = 28f;
			}
			_low.cutoffFrequency = Mathf.Lerp(22000f, 1700f, Mathf.Clamp01(num));
			_low.lowpassResonanceQ = 1f;
			_chorus.depth = Mathf.Lerp(0.05f, 0.8f, Mathf.Clamp01(num));
			_chorus.rate = 0.6f + 0.5f * Mathf.Sin(Time.time * 0.3f);
		}

		public static void Reset()
		{
			if ((Object)(object)_low != (Object)null)
			{
				Object.Destroy((Object)(object)_low);
			}
			if ((Object)(object)_chorus != (Object)null)
			{
				Object.Destroy((Object)(object)_chorus);
			}
			_low = null;
			_chorus = null;
		}
	}
	internal static class Body
	{
		private static Transform _visual;

		private static Quaternion _baseRotation;

		private static GameObject _stars;

		private static ParticleSystem _starSystem;

		private static float _nextHiccup;

		private static float _nextCheer;

		private static Transform _found;

		public static void Pose(Player player)
		{
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			float num = (Plugin.LeanOn.Value ? (Fx.F(25f, 100f) * Fx.Strength) : 0f);
			Transform val = (((Object)(object)player != (Object)null) ? VisualOf(player) : null);
			if ((Object)(object)val == (Object)null || num <= 0.01f)
			{
				Reset();
				return;
			}
			if ((Object)(object)_visual != (Object)(object)val)
			{
				Reset();
				_visual = val;
				_baseRotation = val.localRotation;
			}
			float time = Time.time;
			float num2 = (Mathf.Sin(time * 1.1f) + 0.5f * Mathf.Sin(time * 2.3f + 1f)) * 9f * num;
			float num3 = Mathf.Sin(time * 0.8f + 2f) * 4f * num;
			val.localRotation = _baseRotation * Quaternion.Euler(num3, 0f, num2);
		}

		public static void Tick(Player player, float dt)
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			float time = Time.time;
			float level = Tipsy.Level;
			float num = (Plugin.StarsOn.Value ? (Fx.F(42f, 100f) * Fx.Strength) : 0f);
			if (num > 0.01f)
			{
				MakeStars(player);
				if ((Object)(object)_starSystem != (Object)null)
				{
					EmissionModule emission = _starSystem.emission;
					((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(Mathf.Lerp(3f, 22f, Mathf.Clamp01(num)));
				}
			}
			else if ((Object)(object)_stars != (Object)null)
			{
				Object.Destroy((Object)(object)_stars);
				_stars = null;
				_starSystem = null;
			}
			if (Plugin.HiccupsOn.Value && level >= 28f)
			{
				if (_nextHiccup == 0f)
				{
					_nextHiccup = time + Random.Range(8f, 18f);
				}
				if (time >= _nextHiccup)
				{
					_nextHiccup = time + Mathf.Lerp(30f, 11f, Fx.F(28f, 100f)) * Random.Range(0.7f, 1.3f);
					Fx.Kick = ((Random.value < 0.5f) ? 1f : (-1f));
					((Character)player).Message((MessageType)1, Translations.T((Random.value < 0.5f) ? "skaltavern_hic" : "skaltavern_hic2"), 0, (Sprite)null, false);
				}
			}
			if (Plugin.HiccupsOn.Value && level >= 60f && time >= _nextCheer)
			{
				_nextCheer = time + Random.Range(45f, 100f);
				Vector3 velocity = ((Character)player).GetVelocity();
				if (((Vector3)(ref velocity)).sqrMagnitude < 0.1f && !((Character)player).InAttack() && !((Character)player).IsBlocking() && !((Character)player).InBed())
				{
					player.StartEmote("cheer", true);
				}
			}
		}

		private static void MakeStars(Player player)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: 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_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: 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_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Expected O, but got Unknown
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_stars != (Object)null || (Object)(object)player == (Object)null)
			{
				return;
			}
			Transform val = Find(((Component)player).transform, "Head") ?? ((Component)player).transform;
			_stars = new GameObject("SkalStars");
			_stars.transform.SetParent(val, false);
			_stars.transform.localPosition = (((Object)(object)val == (Object)(object)((Component)player).transform) ? new Vector3(0f, 1.9f, 0f) : new Vector3(0f, 0.12f, 0f));
			ParticleSystem val2 = _stars.AddComponent<ParticleSystem>();
			MainModule main = val2.main;
			((MainModule)(ref main)).loop = true;
			((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(1.6f);
			((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(0f);
			((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.11f);
			((MainModule)(ref main)).startColor = new MinMaxGradient(new Color(1f, 0.85f, 0.3f, 0.95f), new Color(1f, 0.55f, 0.75f, 0.95f));
			((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)0;
			((MainModule)(ref main)).maxParticles = 60;
			ShapeModule shape = val2.shape;
			((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)10;
			((ShapeModule)(ref shape)).radius = 0.4f;
			VelocityOverLifetimeModule velocityOverLifetime = val2.velocityOverLifetime;
			((VelocityOverLifetimeModule)(ref velocityOverLifetime)).enabled = true;
			((VelocityOverLifetimeModule)(ref velocityOverLifetime)).space = (ParticleSystemSimulationSpace)0;
			((VelocityOverLifetimeModule)(ref velocityOverLifetime)).x = MinMaxCurve.op_Implicit(0f);
			((VelocityOverLifetimeModule)(ref velocityOverLifetime)).y = MinMaxCurve.op_Implicit(0.12f);
			((VelocityOverLifetimeModule)(ref velocityOverLifetime)).z = MinMaxCurve.op_Implicit(0f);
			((VelocityOverLifetimeModule)(ref velocityOverLifetime)).orbitalX = MinMaxCurve.op_Implicit(0f);
			((VelocityOverLifetimeModule)(ref velocityOverLifetime)).orbitalY = MinMaxCurve.op_Implicit(2.8f);
			((VelocityOverLifetimeModule)(ref velocityOverLifetime)).orbitalZ = MinMaxCurve.op_Implicit(0f);
			SizeOverLifetimeModule sizeOverLifetime = val2.sizeOverLifetime;
			((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = true;
			((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = new MinMaxCurve(1f, new AnimationCurve((Keyframe[])(object)new Keyframe[3]
			{
				new Keyframe(0f, 0f),
				new Keyframe(0.2f, 1f),
				new Keyframe(1f, 0f)
			}));
			ParticleSystemRenderer component = _stars.GetComponent<ParticleSystemRenderer>();
			ZNetScene instance = ZNetScene.instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				GameObject prefab = instance.GetPrefab("Tankard");
				if (prefab == null)
				{
					obj = null;
				}
				else
				{
					ParticleSystemRenderer componentInChildren = prefab.GetComponentInChildren<ParticleSystemRenderer>(true);
					obj = ((componentInChildren != null) ? ((Renderer)componentInChildren).sharedMaterial : null);
				}
			}
			Material val3 = (Material)obj;
			if ((Object)(object)val3 != (Object)null)
			{
				((Renderer)component).sharedMaterial = val3;
			}
			component.renderMode = (ParticleSystemRenderMode)0;
			_starSystem = val2;
			val2.Play();
		}

		private static Transform VisualOf(Player player)
		{
			if ((Object)(object)_found == (Object)null || !_found.IsChildOf(((Component)player).transform))
			{
				_found = Find(((Component)player).transform, "Visual");
			}
			return _found;
		}

		private static Transform Find(Transform root, string name)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			if (((Object)root).name == name)
			{
				return root;
			}
			foreach (Transform item in root)
			{
				Transform root2 = item;
				Transform val = Find(root2, name);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		public static void Reset()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_visual != (Object)null)
			{
				_visual.localRotation = _baseRotation;
			}
			_visual = null;
			if ((Object)(object)_stars != (Object)null)
			{
				Object.Destroy((Object)(object)_stars);
			}
			_stars = null;
			_starSystem = null;
			_nextHiccup = (_nextCheer = 0f);
		}
	}
	[HarmonyPatch(typeof(GameCamera), "LateUpdate")]
	internal static class GameCamera_Drunk
	{
		private static void Postfix(GameCamera __instance)
		{
			Fx.Camera(__instance);
			Body.Pose(Player.m_localPlayer);
		}
	}
	[BepInPlugin("com.quad.skaltavern", "SkalTavern", "0.5.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.quad.skaltavern";

		public const string OldGuid = "com.dhack.skaltavern";

		public const string Name = "SkalTavern";

		public const string Version = "0.5.0";

		internal static Plugin Instance;

		internal static ManualLogSource Log;

		internal static ServerSettings Synced;

		internal static ConfigEntry<float> SoberMinutes;

		internal static ConfigEntry<float> Sway;

		internal static ConfigEntry<float> Drift;

		internal static ConfigEntry<float> ToastSeconds;

		internal static ConfigEntry<float> Strength;

		internal static ConfigEntry<bool> StumbleOn;

		internal static ConfigEntry<bool> PassOutOn;

		internal static ConfigEntry<bool> HangoverOn;

		internal static ConfigEntry<bool> ScreenFx;

		internal static ConfigEntry<bool> Muffle;

		internal static ConfigEntry<bool> StarsOn;

		internal static ConfigEntry<bool> LeanOn;

		internal static ConfigEntry<bool> HiccupsOn;

		internal static ConfigEntry<bool> SlurOn;

		internal static ConfigEntry<bool> ConfusionOn;

		internal static ConfigEntry<bool> PukeOn;

		private Harmony _harmony;

		internal int AwakeFrame;

		private void Awake()
		{
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Expected O, but got Unknown
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Expected O, but got Unknown
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Expected O, but got Unknown
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0329: Expected O, but got Unknown
			//IL_0339: Unknown result type (might be due to invalid IL or missing references)
			//IL_0343: Expected O, but got Unknown
			Migration.FromOldGuid((BaseUnityPlugin)(object)this, "com.dhack.skaltavern");
			Translations.Load((BaseUnityPlugin)(object)this);
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			AwakeFrame = Time.frameCount;
			Synced = new ServerSettings("com.quad.skaltavern", ((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
			SoberMinutes = Synced.Add<float>(((BaseUnityPlugin)this).Config.Bind<float>("Drinking", "MinutesToSober", 8f, new ConfigDescription("How many minutes it takes to sober up from very drunk (100). Longer and you stay tipsy for longer. In multiplayer the server's value applies.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>())));
			Strength = Synced.Add<float>(((BaseUnityPlugin)this).Config.Bind<float>("Drinking", "EffectStrength", 100f, new ConfigDescription("How strong everything about being drunk is (percent): the picture, the sway, your steering, the sound. 0 for none, 200 for a night you will not remember. In multiplayer the server's value applies.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 300f), Array.Empty<object>())));
			ScreenFx = ((BaseUnityPlugin)this).Config.Bind<bool>("Effects", "Picture", true, "The picture changes as you get drunk: dark edges, colour fringing, blur, double vision, colours that drift.");
			Muffle = ((BaseUnityPlugin)this).Config.Bind<bool>("Effects", "Sound", true, "Sounds go muffled and wobbly as you get drunk.");
			StarsOn = ((BaseUnityPlugin)this).Config.Bind<bool>("Effects", "Stars", true, "Stars circle your head when you are drunk.");
			LeanOn = ((BaseUnityPlugin)this).Config.Bind<bool>("Effects", "Weave", true, "Your body leans and weaves when you are drunk.");
			HiccupsOn = ((BaseUnityPlugin)this).Config.Bind<bool>("Effects", "Hiccups", true, "Hiccups now and then, and a drunken cheer when you stand still.");
			SlurOn = ((BaseUnityPlugin)this).Config.Bind<bool>("Effects", "SlurredChat", true, "What you say in chat comes out slurred when you are drunk.");
			ConfusionOn = Synced.Add<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("Effects", "ReversedControls", true, "Sloshed, your controls reverse for a moment now and then. In multiplayer the server's value applies."));
			PukeOn = Synced.Add<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("Effects", "Puke", true, "Too much drink and you throw up. In multiplayer the server's value applies."));
			Sway = ((BaseUnityPlugin)this).Config.Bind<float>("Drinking", "ScreenSway", 100f, new ConfigDescription("How much the view sways when you are drunk (percent). 0 for none.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), Array.Empty<object>()));
			Drift = Synced.Add<float>(((BaseUnityPlugin)this).Config.Bind<float>("Drinking", "FeetDrift", 100f, new ConfigDescription("How much your walking wanders when you are drunk (percent). 0 for none. In multiplayer the server's value applies.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), Array.Empty<object>())));
			StumbleOn = Synced.Add<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("Drinking", "Stumble", true, "Very drunk, you stagger now and then. In multiplayer the server's value applies."));
			PassOutOn = Synced.Add<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("Drinking", "PassOut", true, "Too much drink knocks you down (and sobers you a little). In multiplayer the server's value applies."));
			HangoverOn = Synced.Add<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("Drinking", "Hangover", true, "After a big night you wake with a hangover: slower stamina and health for a few minutes. In multiplayer the server's value applies."));
			ToastSeconds = Synced.Add<float>(((BaseUnityPlugin)this).Config.Bind<float>("Toast", "Window", 6f, new ConfigDescription("Every swig of a drink is a toast with whoever is near. How many seconds apart two toasts can be and still count as together: friends who drink together (and your companions) get a Skal! buff. In multiplayer the server's value applies.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 20f), Array.Empty<object>())));
			_harmony = new Harmony("com.quad.skaltavern");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			Drinks.Register();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"SkalTavern 0.5.0 loaded");
		}

		private void Update()
		{
			Synced?.Update();
			Toast.UpdateNetwork();
			Tools.Update();
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				Tipsy.Tick(localPlayer, Time.deltaTime);
				Body.Tick(localPlayer, Time.deltaTime);
				Sound.Tick(Tipsy.Level);
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Toast.Unregister();
			Tools.Unregister();
			Tipsy.Clear();
			Fx.Reset();
			Drinks.Unregister();
			Synced?.Dispose();
			Translations.Unload();
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ZNetScene_Awake
	{
		private static void Postfix()
		{
			Drinks.Register();
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class ObjectDB_Awake
	{
		private static void Postfix()
		{
			Drinks.Register();
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
	internal static class ObjectDB_CopyOtherDB
	{
		private static void Postfix()
		{
			Drinks.Register();
		}
	}
	internal static class Swigs
	{
		public const int PerMug = 4;

		public const string Key = "SkalTavern.swigs";

		public static bool IsDrink(ItemData item)
		{
			if (item?.m_shared != null)
			{
				return Drinks.All.Any((Drinks.Def d) => d.Display == item.m_shared.m_name);
			}
			return false;
		}

		public static int Left(ItemData item)
		{
			if (item?.m_customData != null && item.m_customData.TryGetValue("SkalTavern.swigs", out var value) && int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && result >= 1 && result <= 4)
			{
				return result;
			}
			return 4;
		}

		internal static void TakeOne(Inventory inventory, ItemData item)
		{
			int num = Left(item) - 1;
			if (num > 0)
			{
				if (item.m_customData == null)
				{
					item.m_customData = new Dictionary<string, string>();
				}
				item.m_customData["SkalTavern.swigs"] = num.ToString(CultureInfo.InvariantCulture);
				inventory.m_onChanged?.Invoke();
			}
			else
			{
				item.m_customData?.Remove("SkalTavern.swigs");
				inventory.RemoveOneItem(item);
			}
		}
	}
	[HarmonyPatch(typeof(Player), "ConsumeItem")]
	internal static class Player_ConsumeItem_Swig
	{
		[HarmonyPriority(0)]
		private static bool Prefix(Player __instance, Inventory inventory, ItemData item, bool checkWorldLevel, ref bool __result, bool __runOriginal)
		{
			if (!__runOriginal)
			{
				return false;
			}
			if (!Swigs.IsDrink(item))
			{
				return true;
			}
			__result = false;
			if (inventory == null)
			{
				inventory = ((Humanoid)__instance).GetInventory();
			}
			if (!inventory.ContainsItem(item) || !((Humanoid)__instance).CanConsumeItem(item, checkWorldLevel))
			{
				return false;
			}
			if ((Object)(object)item.m_shared.m_consumeStatusEffect != (Object)null)
			{
				((Character)__instance).GetSEMan().AddStatusEffect(item.m_shared.m_consumeStatusEffect, true, 0, 0f, (short)(-1));
			}
			Swigs.TakeOne(inventory, item);
			Toast.Raise(__instance);
			__result = true;
			return false;
		}
	}
	[HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[]
	{
		typeof(ItemData),
		typeof(int),
		typeof(bool),
		typeof(float),
		typeof(int),
		typeof(bool)
	})]
	internal static class ItemData_GetTooltip_Swigs
	{
		private static void Postfix(ItemData item, bool appending, ref string __result)
		{
			if (!appending && Swigs.IsDrink(item))
			{
				__result += $"\n$skaltavern_swigs_left: <color=orange>{Swigs.Left(item)}/{4}</color>";
			}
		}
	}
	internal static class Tipsy
	{
		public static float Level;

		private static float _peak;

		private static float _nextStumble;

		private static float _nextPuke;

		private static readonly int PukeHash = StringExtensionMethods.GetStableHashCode("Puke");

		public static float Wobble => Mathf.InverseLerp(20f, 100f, Level);

		public static string Stage(float level)
		{
			if (!(level < 12f))
			{
				if (!(level < 35f))
				{
					if (!(level < 60f))
					{
						if (!(level < 85f))
						{
							return "Sloshed";
						}
						return "Drunk";
					}
					return "Tipsy";
				}
				return "Merry";
			}
			return "Warm";
		}

		public static string StageName(float level)
		{
			return Stage(level) switch
			{
				"Warm" => Translations.T("skaltavern_stage_warm"), 
				"Merry" => Translations.T("skaltavern_stage_merry"), 
				"Tipsy" => Translations.T("skaltavern_stage_tipsy"), 
				"Drunk" => Translations.T("skaltavern_stage_drunk"), 
				_ => Translations.T("skaltavern_stage_sloshed"), 
			};
		}

		public static void Drink(float amount, float share = 1f)
		{
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				float level = Level;
				if (amount > 0f && level >= 85f && Random.value < 1f - Mathf.Pow(0.6f, share))
				{
					Puke(localPlayer);
					level = Level;
					amount *= 0.5f;
				}
				Level = Mathf.Min(130f, Level + amount);
				_peak = Mathf.Max(_peak, Level);
				SEMan sEMan = ((Character)localPlayer).GetSEMan();
				if (!sEMan.HaveStatusEffect(Drinks.TipsyHash))
				{
					sEMan.AddStatusEffect(Drinks.TipsyHash, false, 0, 0f, (short)(-1));
				}
				if (Stage(level) != Stage(Level))
				{
					((Character)localPlayer).Message((MessageType)1, StageName(Level) + ((Level >= 60f) ? "..." : ""), 0, (Sprite)null, false);
				}
			}
		}

		public static void Tick(Player player, float dt)
		{
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: 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_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_020c: 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_021d: Unknown result type (might be due to invalid IL or missing references)
			SEMan sEMan = ((Character)player).GetSEMan();
			if (((Character)player).IsDead())
			{
				Level = 0f;
				_peak = 0f;
			}
			bool flag = sEMan.HaveStatusEffect(Drinks.TipsyHash);
			if (Level <= 0f)
			{
				if (flag)
				{
					sEMan.RemoveStatusEffect(Drinks.TipsyHash, true);
				}
				return;
			}
			if (!flag)
			{
				sEMan.AddStatusEffect(Drinks.TipsyHash, false, 0, 0f, (short)(-1));
			}
			Level -= 100f / (Plugin.SoberMinutes.Value * 60f) * dt;
			if (Level <= 0f)
			{
				Level = 0f;
				sEMan.RemoveStatusEffect(Drinks.TipsyHash, true);
				if (Plugin.HangoverOn.Value && _peak >= 55f)
				{
					sEMan.AddStatusEffect(Drinks.HangoverHash, true, 0, 0f, (short)(-1));
					((Character)player).Message((MessageType)2, Translations.T("skaltavern_sober_hangover"), 0, (Sprite)null, false);
				}
				_peak = 0f;
			}
			else if (Level >= 100f && Plugin.PassOutOn.Value)
			{
				Puke(player);
				Level = Mathf.Min(Level, 62f);
				((Character)player).Stagger(-((Component)player).transform.forward);
				((Character)player).Message((MessageType)2, Translations.T("skaltavern_pass_out"), 0, (Sprite)null, false);
			}
			else if (Level >= 88f && Time.time >= _nextPuke)
			{
				_nextPuke = Time.time + Random.Range(22f, 42f);
				if (Random.value < 0.5f)
				{
					Puke(player);
				}
			}
			else if (Level >= 75f && Plugin.StumbleOn.Value && Time.time >= _nextStumble)
			{
				_nextStumble = Time.time + Random.Range(10f, 22f);
				if (Random.value < 0.6f && ((Character)player).IsOnGround() && !((Character)player).InPlaceMode())
				{
					Vector2 insideUnitCircle = Random.insideUnitCircle;
					Vector2 normalized = ((Vector2)(ref insideUnitCircle)).normalized;
					((Character)player).Stagger(new Vector3(normalized.x, 0f, normalized.y));
				}
			}
		}

		public static void Puke(Player player)
		{
			if (Plugin.PukeOn.Value && !((Object)(object)player == (Object)null))
			{
				SEMan sEMan = ((Character)player).GetSEMan();
				if (!sEMan.HaveStatusEffect(PukeHash))
				{
					sEMan.AddStatusEffect(PukeHash, true, 0, 0f, (short)(-1));
				}
				Level = Mathf.Max(0f, Level - 14f);
				((Character)player).Message((MessageType)1, Translations.T("skaltavern_puke"), 0, (Sprite)null, false);
			}
		}

		public static void Clear()
		{
			Level = 0f;
			_peak = 0f;
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)localPlayer == (Object)null))
			{
				int[] array = new int[3]
				{
					Drinks.TipsyHash,
					Drinks.HangoverHash,
					Drinks.SkalHash
				};
				foreach (int num in array)
				{
					((Character)localPlayer).GetSEMan().RemoveStatusEffect(num, true);
				}
				Fx.Reset();
			}
		}
	}
	public class SE_Drink : StatusEffect
	{
		public float Amount;

		public float Share = 1f;

		public override void Setup(Character character)
		{
			((StatusEffect)this).Setup(character);
			if ((Object)(object)character == (Object)(object)Player.m_localPlayer)
			{
				Tipsy.Drink(Amount, Share);
			}
		}
	}
	public class SE_Tipsy : SE_Stats
	{
		public override void Setup(Character character)
		{
			((StatusEffect)this).m_ttl = 0f;
			((SE_Stats)this).Setup(character);
			Apply();
		}

		public override void UpdateStatusEffect(float dt)
		{
			Apply();
			((SE_Stats)this).UpdateStatusEffect(dt);
		}

		private void Apply()
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			float level = Tipsy.Level;
			base.m_staminaRegenMultiplier = ((level < 8f) ? 1f : ((level < 70f) ? (1f + 0.25f * Mathf.InverseLerp(8f, 45f, Mathf.Min(level, 45f))) : Mathf.Lerp(1.15f, 0.85f, Mathf.InverseLerp(70f, 110f, level))));
			base.m_healthRegenMultiplier = ((level < 8f) ? 1f : 1.1f);
			base.m_mods.Clear();
			if (level >= 35f)
			{
				base.m_mods.Add(new DamageModPair
				{
					m_type = (DamageType)64,
					m_modifier = (DamageModifier)1
				});
			}
		}

		public override string GetIconText()
		{
			return Tipsy.StageName(Tipsy.Level);
		}

		public override string GetTooltipString()
		{
			return Tipsy.StageName(Tipsy.Level) + "\n" + Translations.T("skaltavern_tipsy_tooltip");
		}
	}
	public class SE_Hangover : SE_Stats
	{
		public override void Setup(Character character)
		{
			((StatusEffect)this).m_ttl = 180f;
			base.m_staminaRegenMultiplier = 0.7f;
			base.m_healthRegenMultiplier = 0.85f;
			((SE_Stats)this).Setup(character);
		}

		public override string GetTooltipString()
		{
			return Translations.T("skaltavern_hangover_tooltip");
		}
	}
	internal static class Toast
	{
		private class Other
		{
			public long Sender;

			public string Name;

			public Vector3 Pos;

			public float At;
		}

		private const string Rpc = "DHack_SkalToast";

		private static readonly List<Other> Others = new List<Other>();

		private static float _last = -999f;

		private static float _nextAllowed;

		private static ZRoutedRpc _on;

		public static int Partners;

		public static void UpdateNetwork()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance == null)
			{
				_on = null;
			}
			else if (!((Object)(object)Plugin.Instance == (Object)null) && Time.frameCount > Plugin.Instance.AwakeFrame + 2 && instance != _on)
			{
				_on = instance;
				Unregister();
				instance.Register<Vector3, string>("DHack_SkalToast", (Action<long, Vector3, string>)OnToast);
			}
		}

		public static void Unregister()
		{
			if (ZRoutedRpc.instance != null)
			{
				if (AccessTools.Field(typeof(ZRoutedRpc), "m_functions").GetValue(ZRoutedRpc.instance) is IDictionary dictionary)
				{
					dictionary.Remove(StringExtensionMethods.GetStableHashCode("DHack_SkalToast"));
				}
				_on = null;
			}
		}

		private static void OnToast(long sender, Vector3 pos, string name)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (sender != ZDOMan.GetSessionID())
			{
				Others.RemoveAll((Other o) => o.Sender == sender);
				Others.Add(new Other
				{
					Sender = sender,
					Name = name,
					Pos = pos,
					At = Time.time
				});
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null)
				{
					Evaluate(localPlayer);
				}
			}
		}

		public static void Raise(Player player)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			if (((Character)player).IsDead())
			{
				return;
			}
			_last = Time.time;
			if (Time.time < _nextAllowed)
			{
				Evaluate(player, say: false);
				return;
			}
			_nextAllowed = Time.time + 6f;
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null)
			{
				instance.InvokeRoutedRPC(0L, "DHack_SkalToast", new object[2]
				{
					((Component)player).transform.position,
					player.GetPlayerName()
				});
			}
			Evaluate(player);
		}

		private static bool Evaluate(Player player, bool say = true)
		{
			float window = Plugin.ToastSeconds.Value;
			if (Time.time - _last > window)
			{
				return false;
			}
			Others.RemoveAll((Other o) => Time.time - o.At > window + 4f);
			List<Other> list = Others.Where((Other o) => Time.time - o.At <= window && Vector3.Distance(o.Pos, ((Component)player).transform.position) < 15f).ToList();
			int num = Character.GetAllCharacters().Count(delegate(Character c)
			{
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)c != (Object)null && !c.IsDead() && Vector3.Distance(((Component)c).transform.position, ((Component)player).transform.position) < 12f)
				{
					ZNetView component = ((Component)c).GetComponent<ZNetView>();
					long? obj;
					if (component == null)
					{
						obj = null;
					}
					else
					{
						ZDO zDO = component.GetZDO();
						obj = ((zDO != null) ? new long?(zDO.GetLong("dhc_id", 0L)) : ((long?)null));
					}
					long? num3 = obj;
					return num3.GetValueOrDefault() != 0;
				}
				return false;
			});
			int num2 = list.Count + Mathf.Min(num, 3);
			if (num2 <= 0)
			{
				return false;
			}
			Partners = Mathf.Min(num2, 4);
			((Character)player).GetSEMan().AddStatusEffect(Drinks.SkalHash, true, 0, 0f, (short)(-1));
			if (!say)
			{
				return true;
			}
			string text = ((list.Count > 0) ? list.Select((Other o) => o.Name).Aggregate((string a, string b) => Translations.T("skaltavern_and", a, b)) : null);
			string text2 = ((text == null) ? Translations.T((num == 1) ? "skaltavern_toast_companion" : "skaltavern_toast_companions") : ((num == 0) ? Translations.T("skaltavern_toast_with", text) : Translations.T((num == 1) ? "skaltavern_toast_with_companion" : "skaltavern_toast_with_companions", text)));
			((Character)player).Message((MessageType)2, text2, 0, (Sprite)null, false);
			return true;
		}
	}
	public class SE_Skal : SE_Stats
	{
		public override void Setup(Character character)
		{
			((StatusEffect)this).m_ttl = 300f;
			int num = Mathf.Clamp(Toast.Partners, 1, 4);
			base.m_staminaRegenMultiplier = 1f + 0.1f * (float)num;
			base.m_healthRegenMultiplier = 1f + 0.08f * (float)num;
			((SE_Stats)this).Setup(character);
		}

		public override string GetTooltipString()
		{
			return Translations.T("skaltavern_skal_tooltip");
		}
	}
	internal static class Tools
	{
		private static BaseUnityPlugin _claudeTools;

		private static float _next;

		public static void Update()
		{
			if (Time.unscaledTime < _next)
			{
				return;
			}
			_next = Time.unscaledTime + 5f;
			PluginInfo value;
			BaseUnityPlugin val = (Chainloader.PluginInfos.TryGetValue("com.quad.claudetools", out value) ? value.Instance : null);
			if ((Object)(object)val == (Object)(object)_claudeTools)
			{
				return;
			}
			_claudeTools = val;
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			try
			{
				((object)val).GetType().GetMethod("RegisterCommand", BindingFlags.Static | BindingFlags.Public)?.Invoke(null, new object[4]
				{
					"SkalTavern",
					"skal",
					"skal status | level <n> | puke | find <text> | drop [drink] | drink [drink] | sober: how drunk the player is; drop a drink from the bag as the game does and say what came of it; drink a swig of one (a quarter: four to a mug); sober up",
					new Func<string[], Action<JObject>, Action<string>, IEnumerator>(Command)
				});
				Plugin.Log.LogInfo((object)"Claude Tools found: skal command added");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not add the skal command to Claude Tools: " + ex.Message));
			}
		}

		public static void Unregister()
		{
			try
			{
				((object)_claudeTools)?.GetType().GetMethod("UnregisterAll", BindingFlags.Static | BindingFlags.Public)?.Invoke(null, new object[1] { "SkalTavern" });
			}
			catch (Exception)
			{
			}
		}

		private static IEnumerator Command(string[] args, Action<JObject> output, Action<string> error)
		{
			Player player = Player.m_localPlayer;
			if ((Object)(object)player == (Object)null)
			{
				error("no player in the world");
				yield break;
			}
			args = args.Skip(1).ToArray();
			string text = ((args.Length != 0) ? args[0].ToLowerInvariant() : "status");
			if (Array.IndexOf(new string[4] { "status", "find", "drink", "drop" }, text) < 0 && !TestCommands.CheatsAllowed())
			{
				error(TestCommands.Refusal("skal " + text));
				yield break;
			}
			string want = ((args.Length > 1) ? args[1] : null);
			switch (text)
			{
			case "sober":
				Tipsy.Clear();
				output(new JObject { ["level"] = JToken.op_Implicit(0) });
				yield break;
			case "level":
			{
				float result;
				float num = ((args.Length > 1 && float.TryParse(args[1], NumberStyles.Float, CultureInfo.InvariantCulture, out result)) ? result : 0f);
				Tipsy.Level = Mathf.Clamp(num, 0f, 130f);
				Tipsy.Drink(0f);
				output(new JObject
				{
					["level"] = JToken.op_Implicit(Tipsy.Level),
					["stage"] = JToken.op_Implicit(Tipsy.Stage(Tipsy.Level))
				});
				yield break;
			}
			case "puke":
				Tipsy.Puke(player);
				output(new JObject { ["level"] = JToken.op_Implicit(Tipsy.Level) });
				yield break;
			case "se":
			{
				StatusEffect val = ((IEnumerable<StatusEffect>)ObjectDB.instance.m_StatusEffects).FirstOrDefault((Func<StatusEffect, bool>)((StatusEffect e) => (Object)(object)e != (Object)null && string.Equals(((Object)e).name, (args.Length > 1) ? args[1] : "", StringComparison.OrdinalIgnoreCase)));
				if ((Object)(object)val == (Object)null)
				{
					error("no status effect of that name");
					yield break;
				}
				JObject val2 = new JObject
				{
					["type"] = JToken.op_Implicit(((object)val).GetType().Name),
					["name"] = JToken.op_Implicit(val.m_name),
					["ttl"] = JToken.op_Implicit(val.m_ttl),
					["tooltip"] = JToken.op_Implicit(val.m_tooltip),
					["startEffects"] = (JToken)new JArray((object)val.m_startEffects.m_effectPrefabs.Select((EffectData p) => (!((Object)(object)p.m_prefab != (Object)null)) ? "-" : ((Object)p.m_prefab).name)),
					["stopEffects"] = (JToken)new JArray((object)val.m_stopEffects.m_effectPrefabs.Select((EffectData p) => (!((Object)(object)p.m_prefab != (Object)null)) ? "-" : ((Object)p.m_prefab).name))
				};
				SE_Stats val3 = (SE_Stats)(object)((val is SE_Stats) ? val : null);
				if (val3 != null)
				{
					val2["staminaRegen"] = JToken.op_Implicit(val3.m_staminaRegenMultiplier);
					val2["healthRegen"] = JToken.op_Implicit(val3.m_healthRegenMultiplier);
					val2["staminaOverTime"] = JToken.op_Implicit(val3.m_staminaOverTime);
					val2["healthOverTime"] = JToken.op_Implicit(val3.m_healthOverTime);
					val2["runDrain"] = JToken.op_Implicit(val3.m_runStaminaDrainModifier);
				}
				output(val2);
				yield break;
			}
			case "find":
			{
				string text2 = ((args.Length > 1) ? args[1] : "").ToLowerInvariant();
				List<string> list = (from g in ZNetScene.instance.m_prefabs
					where (Object)(object)g != (Object)null && ((Object)g).name.ToLowerInvariant().Contains(text2)
					select ((Object)g).name).Take(60).ToList();
				List<string> list2 = (from e in ObjectDB.instance.m_StatusEffects
					where (Object)(object)e != (Object)null && ((Object)e).name.ToLowerInvariant().Contains(text2)
					select ((Object)e).name).Take(40).ToList();
				Animator componentInChildren = ((Component)player).GetComponentInChildren<Animator>();
				List<string> list3 = (((Object)(object)componentInChildren != (Object)null) ? (from p in componentInChildren.parameters
					where p.name.ToLowerInvariant().Contains(text2)
					select p.name).Take(40).ToList() : new List<string>());
				output(new JObject
				{
					["prefabs"] = (JToken)new JArray((object)list),
					["statusEffects"] = (JToken)new JArray((object)list2),
					["animations"] = (JToken)new JArray((object)list3)
				});
				yield break;
			}
			case "status":
				output(new JObject
				{
					["level"] = JToken.op_Implicit(Tipsy.Level),
					["stage"] = JToken.op_Implicit(Tipsy.Stage(Tipsy.Level)),
					["effects"] = (JToken)new JArray((object)(from e in ((Character)player).GetSEMan().GetStatusEffects()
						select ((Object)e).name))
				});
				yield break;
			}
			ItemData item = ((IEnumerable<ItemData>)((Humanoid)player).GetInventory().GetAllItems()).FirstOrDefault((Func<ItemData, bool>)((ItemData i) => (Object)(object)i.m_dropPrefab != (Object)null && ((Object)i.m_dropPrefab).name.StartsWith("dh_drink_") && (want == null || ((Object)i.m_dropPrefab).name.Contains(want))));
			if (item == null)
			{
				error("no drink of ours in the bag" + ((want != null) ? (" matching " + want) : ""));
			}
			else if (text == "drink")
			{
				string drank = ((Object)item.m_dropPrefab).name;
				string name = item.m_shared.m_name;
				int before = ((Humanoid)player).GetInventory().CountItems(name, -1, true);
				int swigsBefore = Swigs.Left(item);
				((Humanoid)player).UseItem(((Humanoid)player).GetInventory(), item, true);
				yield return (object)new WaitForSeconds(2f);
				bool flag = ((Humanoid)player).GetInventory().ContainsItem(item);
				output(new JObject
				{
					["drank"] = JToken.op_Implicit(drank),
					["level"] = JToken.op_Implicit(Tipsy.Level),
					["stage"] = JToken.op_Implicit(Tipsy.Stage(Tipsy.Level)),
					["swigsBefore"] = JToken.op_Implicit(swigsBefore),
					["swigsLeft"] = JToken.op_Implicit(flag ? new int?(Swigs.Left(item)) : ((int?)null)),
					["bagBefore"] = JToken.op_Implicit(before),
					["bagAfter"] = JToken.op_Implicit(((Humanoid)player).GetInventory().CountItems(name, -1, true))
				});
			}
			else if (text == "drop")
			{
				string name = ((Object)item.m_dropPrefab).name;
				int swigsBefore = ((Humanoid)player).GetInventory().CountItems(item.m_shared.m_name, -1, true);
				Vector3 at = ((Component)player).transform.position;
				bool ok = ((Humanoid)player).DropItem(((Humanoid)player).GetInventory(), item, 1);
				yield return (object)new WaitForSeconds(0.8f);
				ItemDrop val4 = FindNear(at, 4f, item.m_shared.m_name);
				ZNetView val5 = (((Object)(object)val4 != (Object)null) ? ((Component)val4).GetComponent<ZNetView>() : null);
				int stableHashCode = StringExtensionMethods.GetStableHashCode(name);
				JObject obj = new JObject
				{
					["drink"] = JToken.op_Implicit(name),
					["dropReturned"] = JToken.op_Implicit(ok),
					["bagBefore"] = JToken.op_Implicit(swigsBefore),
					["bagAfter"] = JToken.op_Implicit(((Humanoid)player).GetInventory().CountItems(item.m_shared.m_name, -1, true)),
					["foundOnGround"] = JToken.op_Implicit((Object)(object)val4 != (Object)null),
					["groundName"] = JToken.op_Implicit(((Object)(object)val4 != (Object)null) ? val4.m_itemData.m_shared.m_name : null),
					["groundNetworked"] = JToken.op_Implicit((Object)(object)val5 != (Object)null && val5.IsValid()),
					["savedAsPrefab"] = JToken.op_Implicit(((Object)(object)val5 != (Object)null && val5.IsValid()) ? new bool?(val5.GetZDO().GetPrefab() == stableHashCode) : ((bool?)null)),
					["sceneKnowsIt"] = JToken.op_Implicit((Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ZNetScene.instance.GetPrefab(stableHashCode) != (Object)null),
					["scenePrefabIsOurs"] = JToken.op_Implicit((Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ZNetScene.instance.GetPrefab(stableHashCode) == (Object)(object)item.m_dropPrefab)
				};
				output(obj);
			}
			else
			{
				error("unknown subcommand " + text);
			}
		}

		private static ItemDrop FindNear(Vector3 at, float range, string sharedName)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			return (from d in Object.FindObjectsOfType<ItemDrop>()
				where (Object)(object)d != (Object)null && d.m_itemData.m_shared.m_name == sharedName && Vector3.Distance(((Component)d).transform.position, at) < range
				orderby Vector3.Distance(((Component)d).transform.position, at)
				select d).FirstOrDefault();
		}
	}
}
namespace DHack.Shared
{
	internal static class Migration
	{
		private sealed class Notice : MonoBehaviour
		{
			public string Text;

			private float _next;

			private void Update()
			{
				if (!(Time.unscaledTime < _next) && !((Object)(object)Player.m_localPlayer == (Object)null) && !((Object)(object)MessageHud.instance == (Object)null))
				{
					((Character)Player.m_localPlayer).Message((MessageType)2, Text, 0, (Sprite)null, false);
					_next = Time.unscaledTime + 60f;
				}
			}
		}

		public static void FromOldGuid(BaseUnityPlugin plugin, string oldGuid)
		{
			BepInPlugin metadata = MetadataHelper.GetMetadata((object)plugin);
			string text = ((metadata != null) ? metadata.GUID : null);
			if (string.IsNullOrEmpty(oldGuid) || string.IsNullOrEmpty(text) || oldGuid == text)
			{
				return;
			}
			ManualLogSource val = Logger.CreateLogSource(text);
			try
			{
				bool flag = false;
				if (Directory.Exists(Paths.ConfigPath))
				{
					string[] files = Directory.GetFiles(Paths.ConfigPath, oldGuid + ".*");
					foreach (string text2 in files)
					{
						string fileName = Path.GetFileName(text2);
						if (!fileName.EndsWith(".cfg") && !fileName.EndsWith(".json") && !fileName.EndsWith(".txt"))
						{
							continue;
						}
						string text3 = Path.Combine(Paths.ConfigPath, text + fileName.Substring(oldGuid.Length));
						if (!File.Exists(text3))
						{
							File.Copy(text2, text3);
							val.LogInfo((object)("Settings moved over from " + fileName + " (the mod's id is now " + text + "; the old file is kept as a backup)"));
							if (fileName == oldGuid + ".cfg")
							{
								flag = true;
							}
						}
					}
				}
				if (flag)
				{
					plugin.Config.Reload();
				}
			}
			catch (Exception ex)
			{
				val.LogWarning((object)("Couldn't move the settings over from " + oldGuid + ".cfg: " + ex.Message));
			}
			finally
			{
				Logger.Sources.Remove((ILogSource)(object)val);
			}
			((MonoBehaviour)plugin).StartCoroutine(StandDownIfTwin(plugin, oldGuid));
		}

		private static IEnumerator StandDownIfTwin(BaseUnityPlugin plugin, string oldGuid)
		{
			yield return null;
			yield return null;
			if (!((Object)(object)plugin == (Object)null) && Chainloader.PluginInfos.TryGetValue(oldGuid, out var value) && !((Object)(object)value.Instance == (Object)null) && !((Object)(object)value.Instance == (Object)(object)plugin))
			{
				BepInPlugin metadata = MetadataHelper.GetMetadata((object)plugin);
				string text = ((metadata != null) ? metadata.Name : null) ?? oldGuid;
				string text2 = (string.IsNullOrEmpty(value.Location) ? "an older copy" : value.Location);
				string text3 = text + ": two copies are installed, an old one (" + text2 + ") and this one. Both would run and do everything twice, so this one stands down. Delete the old copy, then restart the game.";
				Debug.LogError((object)("[" + text + "] " + text3));
				Object.Destroy((Object)(object)plugin);
				GameObject val = new GameObject("Migration_TwoCopies_" + text);
				Object.DontDestroyOnLoad((Object)(object)val);
				val.AddComponent<Notice>().Text = text3;
			}
		}
	}
	internal static class Translations
	{
		public static readonly string[] Shipped = new string[9] { "English", "Russian", "German", "Chinese", "Portuguese_Brazilian", "Spanish", "French", "Polish", "Turkish" };

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

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

		private static string _overrideDir;

		private static bool _hooked;

		private static readonly MethodInfo AddWord = AccessTools.Method(typeof(Localization), "AddWord", (Type[])null, (Type[])null);

		private static readonly FieldInfo Cache = AccessTools.Field(typeof(Localization), "m_cache");

		public static void Load(BaseUnityPlugin plugin)
		{
			Languages.Clear();
			Assembly assembly = ((object)plugin).GetType().Assembly;
			foreach (string item in from n in assembly.GetManifestResourceNames()
				where n.StartsWith("translations/") && n.EndsWith(".json")
				select n)
			{
				using StreamReader streamReader = new StreamReader(assembly.GetManifestResourceStream(item));
				Languages[Path.GetFileNameWithoutExtension(item.Substring("translations/".Length))] = Parse(streamReader.ReadToEnd());
			}
			_english = (Languages.TryGetValue("English", out var value) ? value : new Dictionary<string, string>());
			_overrideDir = Path.Combine(Paths.ConfigPath, "translations", plugin.Info.Metadata.GUID);
			if (!_hooked)
			{
				Localization.OnLanguageChange = (Action)Delegate.Combine(Localization.OnLanguageChange, new Action(Apply));
				_hooked = true;
			}
			Apply();
		}

		public static void Unload()
		{
			if (_hooked)
			{
				Localization.OnLanguageChange = (Action)Delegate.Remove(Localization.OnLanguageChange, new Action(Apply));
				_hooked = false;
			}
		}

		public static string T(string key, params object[] args)
		{
			string text = ((Localization.instance != null) ? Localization.instance.Localize("$" + key) : null);
			if (string.IsNullOrEmpty(text) || text == "[" + key + "]")
			{
				text = (_english.TryGetValue(key, out var value) ? value : key);
			}
			if (args == null || args.Length == 0)
			{
				return text;
			}
			try
			{
				return string.Format(text, args);
			}
			catch (FormatException)
			{
				string value2;
				return _english.TryGetValue(key, out value2) ? SafeFormat(value2, args) : text;
			}
		}

		private static string SafeFormat(string text, object[] args)
		{
			try
			{
				return string.Format(text, args);
			}
			catch (FormatException)
			{
				return text;
			}
		}

		private static void Apply()
		{
			Localization instance = Localization.instance;
			if (instance == null || AddWord == null)
			{
				return;
			}
			string selectedLanguage = instance.GetSelectedLanguage();
			Dictionary<string, string> dictionary = new Dictionary<string, string>(_english);
			if (Languages.TryGetValue(selectedLanguage, out var value))
			{
				foreach (KeyValuePair<string, string> item in value)
				{
					dictionary[item.Key] = item.Value;
				}
			}
			try
			{
				string path = Path.Combine(_overrideDir, selectedLanguage + ".json");
				if (File.Exists(path))
				{
					foreach (KeyValuePair<string, string> item2 in Parse(File.ReadAllText(path)))
					{
						dictionary[item2.Key] = item2.Value;
					}
				}
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("Translations: couldn't read the player's " + selectedLanguage + " file: " + ex.Message));
			}
			foreach (KeyValuePair<string, string> item3 in dictionary)
			{
				AddWord.Invoke(instance, new object[2] { item3.Key, item3.Value });
			}
			object obj = Cache?.GetValue(instance);
			obj?.GetType().GetMethod("EvictAll")?.Invoke(obj, null);
		}

		private static Dictionary<string, string> Parse(string json)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			foreach (Match item in Regex.Matches(json, "\"((?:[^\"\\\\]|\\\\.)*)\"\\s*:\\s*\"((?:[^\"\\\\]|\\\\.)*)\""))
			{
				dictionary[Unescape(item.Groups[1].Value)] = Unescape(item.Groups[2].Value);
			}
			return dictionary;
		}

		private static string Unescape(string s)
		{
			return Regex.Replace(s, "\\\\(u[0-9a-fA-F]{4}|.)", delegate(Match m)
			{
				string value = m.Groups[1].Value;
				return value[0] switch
				{
					'n' => "\n", 
					't' => "\t", 
					'u' => ((char)Convert.ToInt32(value.Substring(1), 16)).ToString(), 
					_ => value, 
				};
			});
		}
	}
	internal sealed class ServerSettings : IDisposable
	{
		private readonly string _send;

		private readonly string _ask;

		private readonly ConfigFile _config;

		private readonly ManualLogSource _log;

		private readonly List<ConfigEntryBase> _entries = new List<ConfigEntryBase>();

		private readonly Dictionary<ConfigEntryBase, object> _own = new Dictionary<ConfigEntryBase, object>();

		private readonly Dictionary<ConfigEntryBase, object> _server = new Dictionary<ConfigEntryBase, object>();

		private ZRoutedRpc _registeredOn;

		private bool _applying;

		private bool _changePending;

		private float _nextChangeSend;

		private const float ChangeSendGap = 0.5f;

		public bool FromServer => _server.Count > 0;

		private static bool IsServer
		{
			get
			{
				if ((Object)(object)ZNet.instance != (Object)null)
				{
					return ZNet.instance.IsServer();
				}
				return false;
			}
		}

		public ServerSettings(string guid, ConfigFile config, ManualLogSource log)
		{
			_send = guid + ".settings";
			_ask = guid + ".settings.ask";
			_config = config;
			_log = log;
		}

		public ConfigEntry<T> Add<T>(ConfigEntry<T> entry)
		{
			if (entry == null || _entries.Contains((ConfigEntryBase)(object)entry))
			{
				return entry;
			}
			_entries.Add((ConfigEntryBase)(object)entry);
			entry.SettingChanged += OnChanged;
			return entry;
		}

		public void Update()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != _registeredOn)
			{
				Unregister();
				Restore();
				_changePending = false;
				if (instance != null)
				{
					Register(instance);
				}
			}
			if (_changePending && Time.unscaledTime >= _nextChangeSend)
			{
				SendChange();
			}
		}

		public void Dispose()
		{
			Unregister();
			Restore();
			foreach (ConfigEntryBase entry in _entries)
			{
				Unsubscribe(entry);
			}
			_entries.Clear();
		}

		private void Register(ZRoutedRpc rpc)
		{
			Forget(rpc, _send);
			Forget(rpc, _ask);
			rpc.Register<ZPackage>(_send, (Action<long, ZPackage>)OnValues);
			rpc.Register(_ask, (Action<long>)OnAsk);
			rpc.m_onNewPeer = (Action<long>)Delegate.Combine(rpc.m_onNewPeer, new Action<long>(OnNewPeer));
			_registeredOn = rpc;
		}

		private void Unregister()
		{
			if (_registeredOn != null)
			{
				ZRoutedRpc registeredOn = _registeredOn;
				registeredOn.m_onNewPeer = (Action<long>)Delegate.Remove(registeredOn.m_onNewPeer, new Action<long>(OnNewPeer));
				Forget(_registeredOn, _send);
				Forget(_registeredOn, _ask);
				_registeredOn = null;
			}
		}

		private static void Forget(ZRoutedRpc rpc, string name)
		{
			if (AccessTools.Field(typeof(ZRoutedRpc), "m_functions")?.GetValue(rpc) is IDictionary dictionary)
			{
				dictionary.Remove(StringExtensionMethods.GetStableHashCode(name));
			}
		}

		private void OnNewPeer(long peer)
		{
			if (IsServer)
			{
				Send(peer);
			}
			else if ((Object)(object)ZNet.instance != (Object)null)
			{
				ZNetPeer serverPeer = ZNet.instance.GetServerPeer();
				if (serverPeer != null && serverPeer.m_uid == peer)
				{
					Ask();
				}
			}
		}

		private void OnAsk(long sender)
		{
			if (IsServer)
			{
				Send(sender);
			}
		}

		private void Ask()
		{
			try
			{
				ZRoutedRpc instance = ZRoutedRpc.instance;
				if (instance != null)
				{
					instance.InvokeRoutedRPC(ZNet.instance.GetServerPeer().m_uid, _ask, Array.Empty<object>());
				}
			}
			catch (Exception)
			{
			}
		}

		private void Send(long target)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			if (ZRoutedRpc.instance == null || _entries.Count == 0)
			{
				return;
			}
			ZPackage val = new ZPackage();
			val.Write(_entries.Count);
			foreach (ConfigEntryBase entry in _entries)
			{
				val.Write(entry.Definition.Section);
				val.Write(entry.Definition.Key);
				val.Write(TomlTypeConverter.ConvertToString(entry.BoxedValue, entry.SettingType));
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(target, _send, new object[1] { val });
		}

		private void OnValues(long sender, ZPackage pkg)
		{
			if (IsServer)
			{
				return;
			}
			ZNetPeer val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetServerPeer() : null);
			if (val == null || val.m_uid != sender)
			{
				return;
			}
			try
			{
				int num = pkg.ReadInt();
				List<string> list = new List<string>();
				for (int i = 0; i < num; i++)
				{
					string section = pkg.ReadString();
					string key = pkg.ReadString();
					string text = pkg.ReadString();
					ConfigEntryBase val2 = ((IEnumerable<ConfigEntryBase>)_entries).FirstOrDefault((Func<ConfigEntryBase, bool>)((ConfigEntryBase x) => x.Definition.Section == section && x.Definition.Key == key));
					if (val2 != null)
					{
						object obj;
						try
						{
							obj = TomlTypeConverter.ConvertToValue(text, val2.SettingType);
						}
						catch (Exception)
						{
							continue;
						}
						if (!_own.ContainsKey(val2))
						{
							_own[val2] = val2.BoxedValue;
						}
						_server[val2] = obj;
						if (!object.Equals(val2.BoxedValue, obj))
						{
							Apply(val2, obj);
							list.Add(section + "/" + key + " = " + text);
						}
					}
				}
				ManualLogSource log = _log;
				if (log != null)
				{
					log.LogInfo((object)($"Settings from the server apply while you play here ({_server.Count})" + ((list.Count > 0) ? (": " + string.Join(", ", list.ToArray())) : "")));
				}
			}
			catch (Exception ex2)
			{
				ManualLogSource log2 = _log;
				if (log2 != null)
				{
					log2.LogWarning((object)("Could not read the server's settings: " + ex2.Message));
				}
			}
		}

		private void Apply(ConfigEntryBase e, object value)
		{
			bool saveOnConfigSet = _config.SaveOnConfigSet;
			_applying = true;
			try
			{
				_config.SaveOnConfigSet = false;
				e.BoxedValue = value;
			}
			finally
			{
				_config.SaveOnConfigSet = saveOnConfigSet;
				_applying = false;
			}
		}

		private void Restore()
		{
			if (_server.Count == 0)
			{
				return;
			}
			foreach (KeyValuePair<ConfigEntryBase, object> item in _own)
			{
				Apply(item.Key, item.Value);
			}
			_own.Clear();
			_server.Clear();
			ManualLogSource log = _log;
			if (log != null)
			{
				log.LogInfo((object)"Your own settings apply again");
			}
		}

		private void OnChanged(object sender, EventArgs args)
		{
			if (_applying)
			{
				return;
			}
			ConfigEntryBase val = (ConfigEntryBase)((sender is ConfigEntryBase) ? sender : null);
			if (val == null)
			{
				return;
			}
			if (_server.TryGetValue(val, out var value))
			{
				_own[val] = val.BoxedValue;
				Apply(val, value);
			}
			else if (IsServer)
			{
				_changePending = true;
				if (Time.unscaledTime >= _nextChangeSend)
				{
					SendChange();
				}
			}
		}

		private void SendChange()
		{
			_changePending = false;
			_nextChangeSend = Time.unscaledTime + 0.5f;
			if (IsServer && ZNet.instance.GetPeers().Count > 0)
			{
				Send(0L);
			}
		}

		private void Unsubscribe(ConfigEntryBase e)
		{
			((object)e).GetType().GetEvent("SettingChanged")?.RemoveEventHandler(e, new EventHandler(OnChanged));
		}
	}
	internal static class TestCommands
	{
		public static bool CheatsAllowed()
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer())
			{
				if ((Object)(object)Console.instance != (Object)null)
				{
					return ((Terminal)Console.instance).IsCheatsEnabled();
				}
				return false;
			}
			return true;
		}

		public static string Refusal(string what)
		{
			return what + " changes the game, so as a test command it only works in single player, for the host, or with devcommands on (a server admin)";
		}
	}
}