Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Quads Skal Tavern v0.5.0
plugins/SkalTavern.dll
Decompiled 3 hours agousing 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)"; } } }