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 DeepSlots v0.1.1
plugins/DeepSlots.dll
Decompiled 2 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [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 DeepSlots { internal sealed class Rules { internal readonly HashSet<ItemType> Types = new HashSet<ItemType>(); internal readonly HashSet<string> Include = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal readonly HashSet<string> Exclude = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal bool AnyItem; internal void Set(string types, string include, string exclude) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) Types.Clear(); Include.Clear(); Exclude.Clear(); foreach (string item in Split(types)) { if (Enum.TryParse<ItemType>(item, ignoreCase: true, out ItemType result)) { Types.Add(result); } } foreach (string item2 in Split(include)) { Include.Add(item2); } foreach (string item3 in Split(exclude)) { Exclude.Add(item3); } } internal static IEnumerable<string> Split(string text) { if (string.IsNullOrEmpty(text)) { yield break; } string[] array = text.Split(new char[3] { ',', ';', '\n' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length > 0) { yield return text2; } } } internal static List<(string item, int amount)> ParseRecipe(string text) { List<(string, int)> list = new List<(string, int)>(); foreach (string item in Split(text)) { int num = item.IndexOf(':'); string text2 = ((num < 0) ? item : item.Substring(0, num)).Trim(); int result = 1; if ((num < 0 || int.TryParse(item.Substring(num + 1).Trim(), out result)) && text2.Length > 0 && result > 0) { list.Add((text2, result)); } } return list; } internal bool Accepts(ItemData item) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (item == null || item.m_shared == null) { return false; } if (AnyItem) { return true; } if (item.m_shared.m_maxStackSize <= 1) { return false; } string prefab = Cells.Prefab(item); string name = item.m_shared.m_name; if (Listed(Exclude, prefab, name)) { return false; } if (Listed(Include, prefab, name)) { return true; } return Types.Contains(item.m_shared.m_itemType); } private static bool Listed(HashSet<string> list, string prefab, string name) { if (list.Count == 0) { return false; } if (prefab != null && list.Contains(prefab)) { return true; } if (name != null) { if (!list.Contains(name)) { if (name.StartsWith("$")) { return list.Contains(name.Substring(1)); } return false; } return true; } return false; } } internal sealed class Box { internal Rules Rules; internal int Cap = 1000000000; internal bool Loading; internal string Kind; internal Dictionary<string, int> Fixed; internal int FixedCount; } internal static class Cells { internal const int DefaultCap = 1000000000; private static readonly ConditionalWeakTable<Inventory, Box> boxes = new ConditionalWeakTable<Inventory, Box>(); internal const int KeyVersion = 1; internal static void Mark(Inventory inventory, Box box) { if (inventory != null) { boxes.Remove(inventory); if (box != null) { boxes.Add(inventory, box); } } } internal static Box Of(Inventory inventory) { if (inventory == null || !boxes.TryGetValue(inventory, out var value)) { return null; } return value; } internal static bool Is(Inventory inventory) { return Of(inventory) != null; } internal static string Prefab(ItemData item) { if (item.m_dropPrefab == null) { return null; } if (!Object.op_Implicit((Object)(object)item.m_dropPrefab)) { return null; } return ((Object)item.m_dropPrefab).name; } internal static int Max(ItemData item) { return Math.Max(1, item.m_shared.m_maxStackSize); } internal static bool Oversized(ItemData item) { if (item != null && item.m_shared != null && item.m_shared.m_maxStackSize > 1) { return item.m_stack > item.m_shared.m_maxStackSize; } return false; } internal static bool Same(ItemData a, ItemData b) { if (a == null || b == null || a.m_shared == null || b.m_shared == null) { return false; } if (a.m_shared.m_name != b.m_shared.m_name || a.m_quality != b.m_quality || a.m_variant != b.m_variant || a.m_worldLevel != b.m_worldLevel) { return false; } Dictionary<string, string> customData = a.m_customData; Dictionary<string, string> customData2 = b.m_customData; int num = customData?.Count ?? 0; int num2 = customData2?.Count ?? 0; if (num != num2) { return false; } if (num == 0) { return true; } foreach (KeyValuePair<string, string> item in customData) { if (!customData2.TryGetValue(item.Key, out var value) || value != item.Value) { return false; } } return true; } internal static ItemData CellOf(Inventory inventory, ItemData like, ItemData except = null) { if (like?.m_shared == null || like.m_shared.m_maxStackSize <= 1) { return null; } foreach (ItemData item in inventory.m_inventory) { if (item != except && Same(item, like)) { return item; } } return null; } internal static bool Inside(Inventory inventory, int x, int y) { if (x >= 0 && y >= 0 && x < inventory.m_width) { return y < inventory.m_height; } return false; } internal static Vector2i FirstEmpty(Inventory inventory, int rows = -1) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if (rows < 0) { rows = inventory.m_height; } for (int i = 0; i < rows; i++) { for (int j = 0; j < inventory.m_width; j++) { if (inventory.GetItemAt(j, i) == null) { return new Vector2i(j, i); } } } return new Vector2i(-1, -1); } internal static void Changed(Inventory inventory) { inventory.Changed(false, false); } private static bool Plain(ItemData i) { if (i.m_quality <= 1 && i.m_variant == 0) { if (i.m_customData != null) { return i.m_customData.Count == 0; } return true; } return false; } internal static int SlotIndex(Box box, ItemData item) { if (box?.Fixed == null || item == null || item.m_shared?.m_name == null || !Plain(item)) { return -1; } if (!box.Fixed.TryGetValue(item.m_shared.m_name, out var value)) { return -1; } return value; } internal static Vector2i At(Inventory inventory, int index) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) return new Vector2i(index % inventory.m_width, index / inventory.m_width); } internal static int SortedRows(int kinds, int width) { return Math.Max(1, (kinds + width) / Math.Max(1, width)); } internal static Vector2i Extra(Inventory inventory, Box box) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_0033: 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_0042: Unknown result type (might be due to invalid IL or missing references) int num = 0; Vector2i val; while (true) { val = At(inventory, num); if (val.y >= 255) { return new Vector2i(-1, -1); } if (inventory.GetItemAt(val.x, val.y) == null) { break; } num++; } if (val.y >= inventory.m_height) { inventory.m_height = val.y + 1; } return val; } private static Vector2i Home(Inventory inventory, Box box, ItemData item, Vector2i? wish) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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) if (box.Fixed != null) { return Extra(inventory, box); } if (wish.HasValue && Inside(inventory, wish.Value.x, wish.Value.y) && inventory.GetItemAt(wish.Value.x, wish.Value.y) == null) { return wish.Value; } return FirstEmpty(inventory); } private static int Compare(Box box, ItemData a, ItemData b) { int num = SlotIndex(box, a); int num2 = SlotIndex(box, b); if (num < 0) { num = int.MaxValue; } if (num2 < 0) { num2 = int.MaxValue; } if (num != num2) { return num.CompareTo(num2); } int num3 = string.CompareOrdinal(a.m_shared.m_name, b.m_shared.m_name); if (num3 != 0) { return num3; } return a.m_quality.CompareTo(b.m_quality); } internal static bool Normalize(Inventory inventory, Box box) { //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) if (box?.Fixed == null) { return false; } List<ItemData> inventory2 = inventory.m_inventory; bool result = false; List<ItemData> list = new List<ItemData>(); for (int i = 0; i < inventory2.Count; i++) { ItemData val = inventory2[i]; if (list.Contains(val) || val.m_shared.m_maxStackSize <= 1) { continue; } for (int j = i + 1; j < inventory2.Count; j++) { ItemData val2 = inventory2[j]; if (!list.Contains(val2) && Same(val, val2)) { val.m_stack = (int)Math.Min(box.Cap, (long)val.m_stack + (long)val2.m_stack); list.Add(val2); } } } foreach (ItemData item in list) { inventory2.Remove(item); result = true; } List<ItemData> list2 = new List<ItemData>(inventory2); list2.Sort((ItemData a, ItemData b) => Compare(box, a, b)); for (int num = 0; num < list2.Count; num++) { Vector2i val3 = At(inventory, num); if (list2[num].m_gridPos.x != val3.x || list2[num].m_gridPos.y != val3.y) { list2[num].m_gridPos = val3; result = true; } } int num2 = SortedRows(list2.Count, inventory.m_width); if (inventory.m_height != num2) { inventory.m_height = num2; result = true; } return result; } private static void Sorted(Inventory inventory, Box box) { if (box.Fixed != null && !box.Loading) { Normalize(inventory, box); } } internal static bool Add(Inventory inventory, Box box, ItemData item, Vector2i? at = null) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) if (item == null || item.m_stack <= 0) { return false; } if (!box.Loading && !box.Rules.Accepts(item)) { return false; } ItemData val = CellOf(inventory, item, item); if (val != null) { long num = (long)box.Cap - (long)val.m_stack; if (num >= item.m_stack) { val.m_stack += item.m_stack; Changed(inventory); return true; } int num2 = (int)Math.Max(0L, num); val.m_stack += num2; item.m_stack -= num2; if (num2 > 0) { Changed(inventory); } return false; } if (inventory.m_inventory.Contains(item)) { return true; } if (item.m_stack > box.Cap) { return false; } Vector2i val2 = Home(inventory, box, item, at); if (val2.x < 0) { return false; } item.m_gridPos = val2; item.m_equipped = false; inventory.m_inventory.Add(item); Sorted(inventory, box); Changed(inventory); return true; } internal static bool AddAt(Inventory inventory, Box box, ItemData item, int amount, int x, int y) { //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) if (item == null) { return false; } amount = Math.Min(amount, item.m_stack); if (amount <= 0) { return false; } if (box.Loading) { return Place(inventory, box, item, amount, x, y); } if (!box.Rules.Accepts(item)) { return false; } ItemData val = (Inside(inventory, x, y) ? inventory.GetItemAt(x, y) : null); if (inventory.m_inventory.Contains(item)) { if (val == item) { return true; } if (box.Fixed != null) { return false; } if (amount < item.m_stack || val != null || !Inside(inventory, x, y)) { return false; } item.m_gridPos = new Vector2i(x, y); Changed(inventory); return true; } ItemData val2 = CellOf(inventory, item); if (val2 != null) { long val3 = (long)box.Cap - (long)val2.m_stack; int num = (int)Math.Max(0L, Math.Min(amount, val3)); val2.m_stack += num; item.m_stack -= num; if (num > 0) { Changed(inventory); } return num == amount; } int num2 = amount; if (amount > box.Cap) { amount = box.Cap; } Vector2i val4 = Home(inventory, box, item, (Vector2i?)new Vector2i(x, y)); if (val4.x < 0) { return false; } ItemData val5 = item.Clone(); val5.m_stack = amount; val5.m_gridPos = val4; val5.m_equipped = false; inventory.m_inventory.Add(val5); item.m_stack -= amount; Sorted(inventory, box); Changed(inventory); return amount == num2; } private static bool Place(Inventory inventory, Box box, ItemData item, int amount, int x, int y) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_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) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) Vector2i val = default(Vector2i); ((Vector2i)(ref val))..ctor(x, y); if (box.Fixed != null) { ItemData val2 = CellOf(inventory, item); if (val2 != null) { val2.m_stack = (int)Math.Min(box.Cap, (long)val2.m_stack + (long)amount); item.m_stack -= amount; return true; } val = Extra(inventory, box); if (val.x < 0) { return false; } } else if (x < 0 || x >= inventory.m_width || y < 0 || inventory.GetItemAt(x, y) != null) { val = FirstEmpty(inventory, inventory.m_height); if (val.x < 0) { val = FirstEmpty(inventory, 255); } if (val.x < 0) { return false; } } ItemData val3 = item.Clone(); val3.m_stack = amount; val3.m_gridPos = val; inventory.m_inventory.Add(val3); item.m_stack -= amount; return true; } internal static bool CanAdd(Inventory inventory, Box box, ItemData item, int stack) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (item == null || !box.Rules.Accepts(item)) { return false; } if (stack <= 0) { stack = item.m_stack; } ItemData val = CellOf(inventory, item, item); if (val != null) { return (long)box.Cap - (long)val.m_stack >= stack; } if (stack > box.Cap) { return false; } if (box.Fixed != null) { return true; } return FirstEmpty(inventory).x >= 0; } internal static int FreeSpace(Inventory inventory, Box box, string name, float worldLevel) { long num = 0L; foreach (ItemData item in inventory.m_inventory) { if (item.m_shared.m_name == name && item.m_shared.m_maxStackSize > 1 && (float)item.m_worldLevel == worldLevel) { num += Math.Max(0L, (long)box.Cap - (long)item.m_stack); } } return (int)Math.Min(2147483647L, num); } internal static int Fill(Inventory inventory, ItemData item, int amount, Vector2i? first = null) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) if (item == null) { return 0; } int num = Max(item); int num2 = Math.Min(amount, item.m_stack); int num3 = num2; if (num3 <= 0) { return 0; } if (first.HasValue && Inside(inventory, first.Value.x, first.Value.y)) { ItemData itemAt = inventory.GetItemAt(first.Value.x, first.Value.y); if (itemAt == null) { num3 -= New(inventory, item, Math.Min(num3, num), first.Value); } else if (itemAt != item && Same(itemAt, item) && itemAt.m_stack < num) { int num4 = Math.Min(num3, num - itemAt.m_stack); itemAt.m_stack += num4; num3 -= num4; } } if (num3 > 0) { ItemData[] array = inventory.m_inventory.ToArray(); foreach (ItemData val in array) { if (num3 <= 0) { break; } if (val != item && Same(val, item) && val.m_stack < num) { int num5 = Math.Min(num3, num - val.m_stack); val.m_stack += num5; num3 -= num5; } } } while (num3 > 0) { Vector2i val2 = inventory.FindEmptySlot(inventory.TopFirst(item)); if (val2.x < 0) { break; } num3 -= New(inventory, item, Math.Min(num3, num), val2); } int num6 = num2 - num3; item.m_stack -= num6; if (num6 > 0) { Changed(inventory); } return num6; } private static int New(Inventory inventory, ItemData item, int n, Vector2i pos) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) ItemData val = item.Clone(); val.m_stack = n; val.m_gridPos = pos; val.m_equipped = false; inventory.m_inventory.Add(val); return n; } internal static bool FillAll(Inventory inventory, ItemData item, Vector2i? first = null) { int stack = item.m_stack; Fill(inventory, item, stack, first); if (item.m_stack > 0) { return false; } item.m_stack = stack; return true; } internal static List<(ItemData item, int stack)> Clamp(Inventory inventory) { List<(ItemData, int)> list = new List<(ItemData, int)>(); foreach (ItemData item in inventory.m_inventory) { if (Oversized(item)) { list.Add((item, item.m_stack)); item.m_stack = item.m_shared.m_maxStackSize; } } return list; } internal static void Restore(List<(ItemData item, int stack)> saved) { foreach (var item3 in saved) { ItemData item = item3.item; int item2 = item3.stack; item.m_stack = item2; } } internal static byte[] SaveCounts(Inventory inventory) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Expected O, but got Unknown List<ItemData> list = new List<ItemData>(); foreach (ItemData item in inventory.m_inventory) { if (Oversized(item)) { list.Add(item); } } if (list.Count == 0) { return new byte[0]; } ZPackage val = new ZPackage(); val.Write(1); val.Write(list.Count); foreach (ItemData item2 in list) { val.Write(item2.m_shared.m_name ?? ""); val.Write(item2.m_quality); val.Write(item2.m_variant); val.Write(item2.m_gridPos.x); val.Write(item2.m_gridPos.y); val.Write(item2.m_stack); } return val.GetArray(); } internal static int ApplyCounts(Inventory inventory, byte[] data) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown if (data == null || data.Length == 0) { return 0; } ZPackage val = new ZPackage(data); if (val.ReadInt() != 1) { return -1; } int num = val.ReadInt(); int num2 = 0; HashSet<ItemData> done = new HashSet<ItemData>(); for (int i = 0; i < num; i++) { string name = val.ReadString(); int quality = val.ReadInt(); int variant = val.ReadInt(); int num3 = val.ReadInt(); int num4 = val.ReadInt(); int num5 = val.ReadInt(); ItemData val2 = null; ItemData itemAt = inventory.GetItemAt(num3, num4); if (itemAt != null && Match(itemAt)) { val2 = itemAt; } else { foreach (ItemData item in inventory.m_inventory) { if (Match(item) && item.m_stack <= Max(item)) { val2 = item; break; } } } if (val2 == null) { num2++; continue; } if (num5 > val2.m_stack) { val2.m_stack = num5; } done.Add(val2); bool Match(ItemData val3) { if (!done.Contains(val3) && val3.m_shared.m_name == name && val3.m_quality == quality) { return val3.m_variant == variant; } return false; } } return num2; } internal static List<(ItemData item, int amount)> DropPlan(IEnumerable<ItemData> items) { List<(ItemData, int)> list = new List<(ItemData, int)>(); foreach (ItemData item in items) { int val = Max(item); int num = item.m_stack; while (num > 0) { int num2 = Math.Min(num, val); list.Add((item, num2)); num -= num2; } } return list; } internal static string Short(long n, bool russian) { if (n < 10000) { return Full(n, russian); } if (n < 1000000) { return Scaled(n, 1000L, "k", russian); } if (n < 1000000000) { return Scaled(n, 1000000L, "M", russian); } return Scaled(n, 1000000000L, "B", russian); } private static string Scaled(long n, long unit, string suffix, bool russian) { long num = n / unit; if (num >= 100) { return num.ToString(CultureInfo.InvariantCulture) + suffix; } long num2 = n * 10 / unit % 10; if (num2 == 0L) { return num.ToString(CultureInfo.InvariantCulture) + suffix; } return num.ToString(CultureInfo.InvariantCulture) + (russian ? "," : ".") + num2.ToString(CultureInfo.InvariantCulture) + suffix; } internal static string Full(long n, bool russian) { string text = Math.Abs(n).ToString(CultureInfo.InvariantCulture); StringBuilder stringBuilder = new StringBuilder(); if (n < 0) { stringBuilder.Append('-'); } for (int i = 0; i < text.Length; i++) { if (i > 0 && (text.Length - i) % 3 == 0) { stringBuilder.Append(russian ? ' ' : ','); } stringBuilder.Append(text[i]); } return stringBuilder.ToString(); } internal static string CopyName(string name, bool russian) { name = (name ?? "").Trim(); if (name.Length > 1 && char.IsUpper(name[0]) && char.IsLower(name[1])) { name = char.ToLowerInvariant(name[0]) + name.Substring(1); } if (!russian) { if (name.Length != 0) { return "Deep " + name; } return "Deep chest"; } if (name.Length == 0) { return "Глубокий сундук"; } string text = "Глубокий "; string[] array = name.Split(new char[2] { ' ', '-' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(',', '.', '(', ')', '«', '»', '"').ToLowerInvariant(); if (text2.Length != 0 && (text2.Length <= 3 || (!text2.EndsWith("ый") && !text2.EndsWith("ий") && !text2.EndsWith("ой") && !text2.EndsWith("ая") && !text2.EndsWith("яя") && !text2.EndsWith("ое") && !text2.EndsWith("ее") && !text2.EndsWith("ые") && !text2.EndsWith("ие")))) { switch (text2[text2.Length - 1]) { case 'а': case 'я': text = "Глубокая "; break; case 'е': case 'о': text = "Глубокое "; break; case 'и': case 'ы': text = "Глубокие "; break; } break; } } return text + name; } } internal static class Hooks { [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class SceneAwake { [HarmonyPriority(200)] private static void Prefix(ZNetScene __instance) { try { Prefabs.Register(__instance); } catch (Exception ex) { Plugin.Warn("ZNetScene: " + ex); } } private static void Postfix() { Prefabs.Hammer(); Words.Refresh(); } } [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class DbAwake { private static void Postfix() { Trophies.Build(force: true); Prefabs.Refresh(); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] private static class DbCopy { private static void Postfix() { Trophies.Build(force: true); Prefabs.Refresh(); } } [HarmonyPatch(typeof(Localization), "SetupLanguage")] private static class Language { private static void Postfix(Localization __instance, string language) { Words.Add(__instance, language); } } [HarmonyPatch(typeof(Container), "Awake")] private static class ContainerAwake { private static void Prefix(Container __instance) { Kind kind = Kinds.ByContainerName(__instance.m_name); if (kind != null && !kind.Copy) { __instance.m_width = kind.Columns.Value; if (kind.FixedLayout) { Trophies.Build(); } __instance.m_height = kind.RowsNow(kind.Columns.Value); } } private static void Postfix(Container __instance) { Kind kind = Kinds.ByContainerName(__instance.m_name); if (kind != null && __instance.m_inventory != null) { Box box = new Box { Rules = kind.Rules, Kind = kind.Id }; if (kind.FixedLayout && Trophies.Slots != null && Trophies.List.Count > 0) { box.Fixed = Trophies.Slots; box.FixedCount = Trophies.List.Count; } Cells.Mark(__instance.m_inventory, box); } } } [HarmonyPatch(typeof(Container), "Save")] private static class ContainerSave { private static bool Prefix(Container __instance) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown Inventory inventory = __instance.m_inventory; if (!Cells.Is(inventory)) { return true; } ZNetView nview = __instance.m_nview; ZDO val = ((nview != null) ? nview.GetZDO() : null); if (val == null) { return false; } ZPackage val2 = new ZPackage(); List<(ItemData, int)> saved = Cells.Clamp(inventory); try { inventory.Save(val2); } finally { Cells.Restore(saved); } val.Set(ZDOVars.s_items, val2.GetArray()); val.Set(CountsKey, Cells.SaveCounts(inventory)); __instance.m_lastRevision = val.DataRevision; return false; } } [HarmonyPatch(typeof(Container), "Load")] private static class ContainerLoad { private static void Prefix(Container __instance, out Box __state) { __state = Cells.Of(__instance.m_inventory); if (__state != null) { __state.Loading = true; } } private static void Postfix(Container __instance, bool __result, Box __state) { if (__state == null) { return; } __state.Loading = false; if (!__result) { return; } ZNetView nview = __instance.m_nview; ZDO val = ((nview != null) ? nview.GetZDO() : null); if (val != null) { int num = Cells.ApplyCounts(__instance.m_inventory, val.GetByteArray(CountsKey, (byte[])null)); if (num != 0) { Plugin.Warn($"{((Object)__instance).name}: {num} saved counts did not match an item"); } Cells.Normalize(__instance.m_inventory, __state); } } private static Exception Finalizer(Exception __exception, Box __state) { if (__state != null) { __state.Loading = false; } return __exception; } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })] private static class AddItem { private static bool Prefix(Inventory __instance, ItemData item, ref bool __result) { if (item == null) { return true; } Box box = Cells.Of(__instance); if (box != null) { if (!box.Loading && !box.Rules.Accepts(item)) { Say("deep_refused"); __result = false; return false; } __result = Cells.Add(__instance, box, item); return false; } if (!Cells.Oversized(item)) { return true; } __result = Cells.FillAll(__instance, item); return false; } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData), typeof(Vector2i) })] private static class AddItemAt { private static bool Prefix(Inventory __instance, ItemData item, Vector2i pos, ref bool __result) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (item == null) { return true; } Box box = Cells.Of(__instance); if (box != null) { if (!box.Loading && !box.Rules.Accepts(item)) { Say("deep_refused"); __result = false; return false; } __result = Cells.Add(__instance, box, item, pos); return false; } if (!Cells.Oversized(item)) { return true; } __result = Cells.FillAll(__instance, item, pos); return false; } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData), typeof(int), typeof(int), typeof(int), typeof(bool) })] private static class AddItemAmount { private static bool Prefix(Inventory __instance, ItemData item, int amount, int x, int y, ref bool __result) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (item == null) { return true; } Box box = Cells.Of(__instance); if (box != null) { if (!box.Loading && !box.Rules.Accepts(item)) { Say("deep_refused"); __result = false; return false; } __result = Cells.AddAt(__instance, box, item, amount, x, y); return false; } if (!Cells.Oversized(item) || amount <= item.m_shared.m_maxStackSize) { return true; } int num = Math.Min(amount, item.m_stack); __result = Cells.Fill(__instance, item, num, (Vector2i?)new Vector2i(x, y)) == num; return false; } } [HarmonyPatch(typeof(Inventory), "CanAddItem", new Type[] { typeof(ItemData), typeof(int) })] private static class CanAddItem { private static bool Prefix(Inventory __instance, ItemData item, int stack, ref bool __result) { Box box = Cells.Of(__instance); if (box == null) { return true; } __result = Cells.CanAdd(__instance, box, item, stack); return false; } } [HarmonyPatch(typeof(Inventory), "FindFreeStackSpace")] private static class FreeStackSpace { private static bool Prefix(Inventory __instance, string name, float worldLevel, ref int __result) { Box box = Cells.Of(__instance); if (box == null) { return true; } __result = Cells.FreeSpace(__instance, box, name, worldLevel); return false; } } [HarmonyPatch(typeof(InventoryGui), "SetupDragItem")] private static class DragItem { private static void Prefix(ItemData item, Inventory inventory, ref int amount) { if (item != null && !fromSplit && Cells.Is(inventory)) { int num = Cells.Max(item); if (amount > num) { amount = num; } } } } [HarmonyPatch(typeof(InventoryGui), "OnSplitOk")] private static class SplitOk { private static void Prefix() { fromSplit = true; } private static void Finalizer() { fromSplit = false; } } [HarmonyPatch(typeof(InventoryGrid), "DropItem")] private static class GridDrop { private static bool Prefix(InventoryGrid __instance, Inventory fromInventory, ItemData item, int amount, Vector2i pos, ref bool __result) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = __instance.m_inventory; Box box = Cells.Of(inventory); Box box2 = Cells.Of(fromInventory); if ((box == null && box2 == null) || item == null || fromInventory == null) { return true; } if (inventory == fromInventory && box.Fixed != null) { __result = true; return false; } if (inventory == fromInventory) { ItemData itemAt = inventory.GetItemAt(pos.x, pos.y); if (itemAt != item) { if (itemAt != null) { itemAt.m_gridPos = item.m_gridPos; } item.m_gridPos = pos; Cells.Changed(inventory); } __result = true; return false; } amount = Math.Min(amount, item.m_stack); int stack = item.m_stack; if (box != null) { if (!box.Rules.Accepts(item)) { Say("deep_refused"); __result = false; return false; } Cells.AddAt(inventory, box, item, amount, pos.x, pos.y); } else { Cells.Fill(inventory, item, amount, pos); } int num = stack - item.m_stack; if (item.m_stack <= 0) { fromInventory.RemoveItem(item); } else if (num > 0) { Cells.Changed(fromInventory); } if (num < amount) { Say("deep_noroom"); } __result = num > 0; return false; } } [HarmonyPatch(typeof(Humanoid), "DropItem")] private static class GroundDrop { private static void Prefix(Humanoid __instance, Inventory inventory, ItemData item, ref int amount) { if (item != null && Cells.Is(inventory)) { int num = Cells.Max(item); if (amount > num) { amount = num; } } } } [HarmonyPatch(typeof(InventoryGrid), "UpdateGui")] private static class GridNumbers { private static void Postfix(InventoryGrid __instance) { Inventory inventory = __instance.m_inventory; if (!Cells.Is(inventory)) { return; } bool russian = Plugin.Russian; int width = inventory.GetWidth(); foreach (ItemData item in inventory.m_inventory) { if (item.m_shared.m_maxStackSize > 1) { InventoryElement element = __instance.GetElement(item.m_gridPos.x, item.m_gridPos.y, width); if (!((Object)(object)element == (Object)null) && !((Object)(object)element.m_amount == (Object)null)) { ((Behaviour)element.m_amount).enabled = true; element.m_amount.text = Cells.Short(item.m_stack, russian); } } } } } [HarmonyPatch(typeof(InventoryGui), "UpdateContainer")] private static class TrophyWindow { private static void Prefix(InventoryGui __instance) { Container currentContainer = __instance.m_currentContainer; if (!((Object)(object)currentContainer == (Object)null) && currentContainer.IsOwner()) { Box box = Cells.Of(currentContainer.m_inventory); if (box?.Fixed != null && Cells.Normalize(currentContainer.m_inventory, box)) { Cells.Changed(currentContainer.m_inventory); } } } private static void Postfix(InventoryGui __instance) { Container currentContainer = __instance.m_currentContainer; if (!((Object)(object)currentContainer == (Object)null) && !((Object)(object)__instance.m_containerName == (Object)null)) { Box box = Cells.Of(currentContainer.m_inventory); if (box?.Fixed != null) { __instance.m_containerName.text = Localization.instance.Localize(currentContainer.m_inventory.GetName()) + " " + Trophies.Collected(currentContainer.m_inventory) + " / " + box.FixedCount; } } } } [HarmonyPatch(typeof(InventoryGrid), "CreateItemTooltip")] private static class GridTooltip { private static bool Prefix(InventoryGrid __instance, ItemData item, UITooltip tooltip) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if (item == null || (Object)(object)tooltip == (Object)null || item.m_shared.m_maxStackSize <= 1 || !Cells.Is(__instance.m_inventory)) { return true; } string text = Localization.instance.Localize("$deep_total") + ": <color=orange>" + Cells.Full(item.m_stack, Plugin.Russian) + "</color>"; tooltip.Set(item.m_shared.m_name, item.GetTooltip(-1) + "\n\n" + text, __instance.m_tooltipAnchor, default(Vector2)); return false; } } [HarmonyPatch(typeof(Container), "GetHoverText")] private static class Hover { private static void Postfix(Container __instance, ref string __result) { Inventory inventory = __instance.m_inventory; if (Cells.Is(inventory) && __result != null) { int num = inventory.NrOfItems(); int num2 = inventory.GetWidth() * inventory.GetHeight(); Box box = Cells.Of(inventory); string text = ((box.Fixed != null) ? ("\n$deep_collected: " + Trophies.Collected(inventory) + " / " + box.FixedCount) : ("\n$deep_cells: " + num + "/" + num2)); if (num > 0 && Plugin.Protect.Value) { text += "\n$deep_noremove"; } __result += Localization.instance.Localize(text); } } } [HarmonyPatch(typeof(Container), "CanBeRemoved")] private static class Removable { private static void Postfix(Container __instance, ref bool __result) { if (__result && Plugin.Protect.Value && Cells.Is(__instance.m_inventory) && __instance.m_inventory.NrOfItems() > 0) { __result = false; } } } [HarmonyPatch(typeof(WearNTear), "ApplyDamage")] private static class NoDamage { private static bool Prefix(WearNTear __instance, ref bool __result) { if (!Plugin.Protect.Value) { return true; } Piece piece = __instance.m_piece; if ((Object)(object)piece == (Object)null || piece.m_name == null || !piece.m_name.StartsWith("$deep_", StringComparison.Ordinal)) { return true; } Container componentInChildren = ((Component)__instance).GetComponentInChildren<Container>(); if ((Object)(object)componentInChildren == (Object)null || !Cells.Is(componentInChildren.m_inventory) || componentInChildren.m_inventory.NrOfItems() == 0) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(Container), "OnDestroyed")] private static class Broken { private static bool Prefix(Container __instance) { //IL_008f: Unknown result type (might be due to invalid IL or missing references) Inventory inventory = __instance.m_inventory; if (!Cells.Is(inventory)) { return true; } if (!__instance.m_nview.IsOwner()) { return false; } List<ItemData> list = new List<ItemData>(); foreach (ItemData item in inventory.m_inventory) { list.Add(item.Clone()); } inventory.RemoveAll(); __instance.Save(); if (list.Count > 0 && (Object)(object)Plugin.Instance != (Object)null) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(Spill(list, ((Component)__instance).transform.position)); } return false; } } internal static readonly int CountsKey = StringExtensionMethods.GetStableHashCode("chistix_deepslots_counts"); private static float lastMessage; private static bool fromSplit; private const int SpillPerFrame = 8; internal static void Say(string key) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !(Time.time - lastMessage < 0.5f)) { lastMessage = Time.time; ((Character)localPlayer).Message((MessageType)2, "$" + key, 0, (Sprite)null, false); } } private static IEnumerator Spill(List<ItemData> items, Vector3 at) { //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) int n = 0; int total = 0; foreach (var (val, num) in Cells.DropPlan(items)) { if (!((Object)(object)val.m_dropPrefab == (Object)null)) { Vector3 val2 = at + Vector3.up * 0.5f + Random.insideUnitSphere * 0.5f; ItemDrop.DropItem(val, num, val2, Quaternion.Euler(0f, (float)Random.Range(0, 360), 0f)); total++; int num2 = n + 1; n = num2; if (num2 >= 8) { n = 0; yield return null; } } } Plugin.Debug($"spilled {total} stacks"); } } internal sealed class Kind { internal string Id; internal string Source; internal string Fallback; internal string IconItem; internal string Section; internal string En; internal string Ru; internal string DescEn; internal string DescRu; internal int DefColumns; internal int DefRows; internal bool FixedLayout; internal string DefTypes; internal string DefInclude; internal string DefExclude; internal string DefRecipe; internal readonly Rules Rules = new Rules(); internal ConfigEntry<bool> Enabled; internal ConfigEntry<int> Columns; internal ConfigEntry<int> Rows; internal ConfigEntry<string> Types; internal ConfigEntry<string> Include; internal ConfigEntry<string> Exclude; internal ConfigEntry<string> Recipe; internal ConfigEntry<string> Station; internal bool Copy; internal Piece SourcePiece; internal string Name => "$" + Id; internal int Hash => StringExtensionMethods.GetStableHashCode(Id); internal bool On { get { if (!Copy) { return Enabled.Value; } return Kinds.CopiesEnabled.Value; } } internal int RowsNow(int width) { if (!FixedLayout) { if (Rows == null) { return DefRows; } return Rows.Value; } return Cells.SortedRows(0, width); } internal void Bind(ConfigFile config) { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Expected O, but got Unknown //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Expected O, but got Unknown ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes { CustomDrawer = Plugin.Stepper }; Enabled = config.Bind<bool>(Section, "Enabled", true, En + " in the hammer's menu. Off: it is not built any more; the ones standing keep working.\n«" + Ru + "» в меню молотка. Выключено: новые не строятся, стоящие работают как прежде."); Columns = config.Bind<int>(Section, "Columns", DefColumns, new ConfigDescription("Cells in a row. Applies to a chest when it is loaded again (come back to the area or log in again); items never get lost, a narrower grid moves them to free cells.\nЯчеек в ряду. Применяется к сундуку, когда он загрузится заново (вернуться в эту местность или перезайти); предметы не теряются, при более узкой сетке они переезжают в свободные ячейки.", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[4] { 5, 6, 7, 8 }), new object[1] { configurationManagerAttributes })); if (!FixedLayout) { Rows = config.Bind<int>(Section, "Rows", DefRows, new ConfigDescription("Rows of cells (over 4 the game's window scrolls). Applies when the chest is loaded again.\nРядов ячеек (больше 4 - родное окно прокручивается). Применяется, когда сундук загрузится заново.", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[9] { 2, 3, 4, 5, 6, 7, 8, 9, 10 }), new object[1] { configurationManagerAttributes })); } Types = config.Bind<string>(Section, "ItemTypes", DefTypes, "Item types it takes, comma-separated (the game's names: Material, Trophy, Consumable, Ammo, Fish...). Only stackable items, never tools, weapons or armour.\nТипы предметов, которые он принимает, через запятую (названия игры: Material, Trophy, Consumable, Ammo, Fish...). Только стакаемые предметы, никогда инструменты, оружие и броня."); Include = config.Bind<string>(Section, "AlsoAccept", DefInclude, "Prefab names it takes besides the types, comma-separated (e.g. Coins, Raspberry).\nИмена префабов, которые он принимает сверх типов, через запятую (например Coins, Raspberry)."); Exclude = config.Bind<string>(Section, "NeverAccept", DefExclude, "Prefab names it never takes, comma-separated (over the types and AlsoAccept).\nИмена префабов, которые он никогда не принимает, через запятую (важнее типов и AlsoAccept)."); Recipe = config.Bind<string>(Section, "Recipe", DefRecipe, "Price to build: Prefab:amount, comma-separated. A wrong name is left out (see the log).\nЦена постройки: Префаб:количество через запятую. Неверное имя пропускается (см. журнал)."); Station = config.Bind<string>(Section, "Station", "piece_workbench", new ConfigDescription("The crafting station that must be near to build it; none: no station.\nСтанция, рядом с которой его можно строить; none - без станции.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[7] { "piece_workbench", "forge", "piece_stonecutter", "piece_artisanstation", "blackforge", "piece_magetable", "none" }), new object[1] { configurationManagerAttributes })); Rules.Set(Types.Value, Include.Value, Exclude.Value); } internal void Reload() { Rules.Set(Types.Value, Include.Value, Exclude.Value); } } internal static class Kinds { internal static readonly Kind Wood = new Kind { Id = "deep_woodstore", Source = "piece_chest", IconItem = "Wood", Section = "Woodstore", En = "Woodstore", Ru = "Дровяной склад", DescEn = "Wood, stone, ore and other resources. Every cell keeps one kind of item with no stack limit (up to 1 billion).", DescRu = "Дерево, камень, руда и другие ресурсы. В каждой ячейке один вид предмета без предела стопки (до 1 млрд).", DefColumns = 8, DefRows = 4, DefTypes = "Material", DefInclude = "", DefExclude = "", DefRecipe = "Wood:15,Stone:10" }; internal static readonly Kind Trophy = new Kind { Id = "deep_trophychest", Source = "itemstand", Fallback = "piece_chest_wood", IconItem = "TrophyDeer", Section = "TrophyChest", En = "Trophy chest", Ru = "Сундук трофеев", DescEn = "Hangs on a wall. Trophies only, every kind in one cell, as many as you have, in the order of the biomes; always a free cell for the next new kind. Shift + E shows one of its trophies on the plaque.", DescRu = "Вешается на стену. Только трофеи: каждый вид в одной ячейке, сколько бы их ни было, по порядку биомов; всегда есть свободная ячейка под новый вид. Shift + E - показать на подставке один из его трофеев.", FixedLayout = true, DefColumns = 8, DefRows = 6, DefTypes = "Trophy", DefInclude = "", DefExclude = "", DefRecipe = "Wood:10,Resin:4" }; internal static readonly Kind[] All = new Kind[2] { Wood, Trophy }; internal static readonly List<Kind> Copies = new List<Kind>(); internal const string CopyPrefix = "deep_copy_"; internal static ConfigEntry<bool> CopiesEnabled; internal static ConfigEntry<int> CopyCost; internal static IEnumerable<Kind> Every() { Kind[] all = All; for (int i = 0; i < all.Length; i++) { yield return all[i]; } foreach (Kind copy in Copies) { yield return copy; } } internal static void BindCopies(ConfigFile config) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown ConfigurationManagerAttributes configurationManagerAttributes = new ConfigurationManagerAttributes { CustomDrawer = Plugin.Stepper }; CopiesEnabled = config.Bind<bool>("Copies", "Enabled", true, "A Deep copy of every chest of the hammer (wooden, reinforced, black metal, personal, barrel... and other mods' chests): the same model and number of cells, but a cell has no stack limit (up to 1 billion), one kind of item per cell. Any item goes in. Off: the copies leave the hammer's menu, the ones standing keep working.\n«Глубокая» копия каждого сундука молотка (деревянный, укреплённый, из чёрного металла, личный, бочка... и сундуки других модов): та же модель и столько же ячеек, но в ячейке нет предела стопки (до 1 млрд), один вид предмета в ячейке. Принимает любые предметы. Выключено: копии пропадают из меню молотка, стоящие работают как прежде."); int[] array = new int[99]; for (int i = 0; i < array.Length; i++) { array[i] = i + 2; } CopyCost = config.Bind<int>("Copies", "CostMultiplier", 5, new ConfigDescription("A copy costs the original's price times this (2x to 100x), at the original's crafting station.\nКопия стоит как оригинал, умноженный на это число (от 2x до 100x), у той же станции.", (AcceptableValueBase)(object)new AcceptableValueList<int>(array), new object[1] { configurationManagerAttributes })); } internal static Kind ByContainerName(string name) { if (string.IsNullOrEmpty(name) || !name.StartsWith("$deep_", StringComparison.Ordinal)) { return null; } foreach (Kind item in Every()) { if (item.Name == name) { return item; } } return null; } internal static Kind ByPrefab(string prefab) { foreach (Kind item in Every()) { if (item.Id == prefab) { return item; } } return null; } } internal sealed class ConfigurationManagerAttributes { public Action<ConfigEntryBase> CustomDrawer; } [BepInPlugin("chistix.deepslots", "Deep Slots", "0.1.1")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "chistix.deepslots"; public const string Version = "0.1.1"; private static ManualLogSource log; internal static Plugin Instance; internal static ConfigEntry<bool> Protect; internal static ConfigEntry<bool> DebugLog; private static GUIStyle centred; internal static bool Russian { get { if (Localization.instance != null) { return Localization.instance.GetSelectedLanguage() == "Russian"; } return false; } } private void Awake() { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) log = ((BaseUnityPlugin)this).Logger; Instance = this; Protect = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ProtectWhileFilled", true, "A chest that holds anything takes no damage (monsters, weather, a lost support) and cannot be dismantled; empty, it is a normal piece. Off: when it breaks, its contents fall out in the game's stacks, a few per frame.\nСундук, в котором что-то лежит, не получает урона (монстры, погода, потеря опоры) и не разбирается; пустой - обычная постройка. Выключено: при разрушении содержимое выпадает обычными стопками игры, по несколько за кадр."); DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLog", false, "More details in the log.\nПодробности в журнал."); Kind[] all = Kinds.All; for (int i = 0; i < all.Length; i++) { all[i].Bind(((BaseUnityPlugin)this).Config); } Kinds.BindCopies(((BaseUnityPlugin)this).Config); ((BaseUnityPlugin)this).Config.SettingChanged += delegate(object _, SettingChangedEventArgs args) { ConfigDefinition s = args.ChangedSetting.Definition; Kind kind = Kinds.All.FirstOrDefault((Kind k) => k.Section == s.Section); if (s.Section == "Copies") { Prefabs.Refresh(); } else if (kind != null) { kind.Reload(); Prefabs.Refresh(); } }; new Harmony("chistix.deepslots").PatchAll(typeof(Plugin).Assembly); Log("Deep Slots 0.1.1"); } private void Start() { try { MethodInfo methodInfo = (from a in AppDomain.CurrentDomain.GetAssemblies() select a.GetType("ValheimUnified.StackLimits", throwOnError: false)).FirstOrDefault((Type t) => t != null)?.GetMethod("Register", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(string), typeof(Func<Inventory, ItemData, int>) }, null); if (!(methodInfo == null)) { Func<Inventory, ItemData, int> func = delegate(Inventory inventory, ItemData item) { Box box = Cells.Of(inventory); return (box != null && item?.m_shared != null && item.m_shared.m_maxStackSize > 1 && box.Rules.Accepts(item)) ? box.Cap : 0; }; methodInfo.Invoke(null, new object[2] { "chistix.deepslots", func }); Log("ValheimUnified: stack limits of the deep chests registered"); } } catch (Exception ex) { Warn("ValheimUnified stack limits: " + ex.Message); } } internal static void Stepper(ConfigEntryBase entry) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown AcceptableValueBase acceptableValues = entry.Description.AcceptableValues; if (((object)acceptableValues)?.GetType().GetProperty("AcceptableValues")?.GetValue(acceptableValues, null) is Array { Length: not 0 } array) { int num = Array.IndexOf(array, entry.BoxedValue); if (centred == null) { centred = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4 }; } if (GUILayout.Button("‹", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(28f) })) { entry.BoxedValue = array.GetValue((Math.Max(num, 0) - 1 + array.Length) % array.Length); } GUILayout.Label(entry.BoxedValue?.ToString() ?? "", centred, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.MinWidth(120f), GUILayout.ExpandWidth(true) }); if (GUILayout.Button("›", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(28f) })) { entry.BoxedValue = array.GetValue((num + 1) % array.Length); } } else { GUILayout.Label(entry.BoxedValue?.ToString() ?? "", Array.Empty<GUILayoutOption>()); } } internal static void Log(string text) { ManualLogSource obj = log; if (obj != null) { obj.LogInfo((object)text); } } internal static void Warn(string text) { ManualLogSource obj = log; if (obj != null) { obj.LogWarning((object)text); } } internal static void Debug(string text) { if (DebugLog != null && DebugLog.Value) { ManualLogSource obj = log; if (obj != null) { obj.LogInfo((object)text); } } } } internal static class Prefabs { private static GameObject holder; internal static readonly Dictionary<string, GameObject> Built = new Dictionary<string, GameObject>(StringComparer.Ordinal); private static Dictionary<string, GameObject> scenePrefabs; private static readonly Dictionary<Sprite, Sprite> badged = new Dictionary<Sprite, Sprite>(); private static readonly HashSet<Sprite> ours = new HashSet<Sprite>(); private const int IconSize = 128; internal static void Register(ZNetScene scene) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown if ((Object)(object)scene == (Object)null || scene.m_prefabs == null) { return; } scenePrefabs = new Dictionary<string, GameObject>(StringComparer.Ordinal); foreach (GameObject prefab in scene.m_prefabs) { if ((Object)(object)prefab != (Object)null && !scenePrefabs.ContainsKey(((Object)prefab).name)) { scenePrefabs[((Object)prefab).name] = prefab; } } if ((Object)(object)holder == (Object)null) { holder = new GameObject("DeepSlots prefabs"); holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)holder); } FindCopies(); foreach (Kind item in Kinds.Every()) { if (!Built.TryGetValue(item.Id, out var value) || (Object)(object)value == (Object)null) { value = Make(item); if ((Object)(object)value == (Object)null) { continue; } Built[item.Id] = value; } if (scenePrefabs.TryGetValue(item.Id, out var value2) && (Object)(object)value2 != (Object)(object)value) { Plugin.Warn("prefab name taken by another mod: " + item.Id); continue; } if (!scene.m_prefabs.Contains(value)) { scene.m_prefabs.Add(value); } scenePrefabs[item.Id] = value; } Refresh(); } private static void FindCopies() { if (Kinds.Copies.Count > 0 || !scenePrefabs.TryGetValue("Hammer", out var value) || (Object)(object)value == (Object)null) { return; } PieceTable val = value.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_buildPieces; if ((Object)(object)val == (Object)null) { return; } SortedSet<string> sortedSet = new SortedSet<string>(StringComparer.Ordinal); foreach (GameObject piece in val.m_pieces) { if (!((Object)(object)piece == (Object)null) && !((Object)piece).name.StartsWith("deep_", StringComparison.Ordinal)) { Piece component = piece.GetComponent<Piece>(); Container componentInChildren = piece.GetComponentInChildren<Container>(true); if (!((Object)(object)component == (Object)null) && !((Object)(object)componentInChildren == (Object)null) && !((Object)(object)piece.GetComponentInChildren<Vagon>(true) != (Object)null) && !((Object)(object)piece.GetComponentInChildren<Ship>(true) != (Object)null) && !((Object)(object)piece.GetComponentInChildren<Incinerator>(true) != (Object)null) && componentInChildren.m_width * componentInChildren.m_height > 0) { sortedSet.Add(((Object)piece).name); } } } foreach (string item in sortedSet) { GameObject val2 = scenePrefabs[item]; Kind kind = new Kind { Id = "deep_copy_" + item, Source = item, Copy = true, SourcePiece = val2.GetComponent<Piece>() }; kind.Rules.AnyItem = true; Kinds.Copies.Add(kind); } Plugin.Log(string.Format("deep copies of {0} chests: {1}", Kinds.Copies.Count, string.Join(", ", sortedSet))); } private static GameObject Make(Kind kind) { //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Expected O, but got Unknown //IL_01ce: Unknown result type (might be due to invalid IL or missing references) if (!scenePrefabs.TryGetValue(kind.Source, out var value) || (Object)(object)value == (Object)null) { if (kind.Fallback == null || !scenePrefabs.TryGetValue(kind.Fallback, out value) || (Object)(object)value == (Object)null) { Plugin.Warn(kind.Id + ": no " + kind.Source + " in the game"); return null; } Plugin.Warn(kind.Id + ": no " + kind.Source + ", made from " + kind.Fallback); } GameObject val = Object.Instantiate<GameObject>(value, holder.transform, false); ((Object)val).name = kind.Id; val.transform.localPosition = Vector3.zero; Container val2 = val.GetComponentInChildren<Container>(true); if ((Object)(object)val2 == (Object)null && (Object)(object)val.GetComponent<ItemStand>() != (Object)null) { val2 = val.AddComponent<Container>(); GameObject value2; Container val3 = (scenePrefabs.TryGetValue("piece_chest_wood", out value2) ? value2.GetComponentInChildren<Container>(true) : null); if ((Object)(object)val3 != (Object)null) { val2.m_bkg = val3.m_bkg; val2.m_openEffects = val3.m_openEffects; val2.m_closeEffects = val3.m_closeEffects; } ItemStand component = val.GetComponent<ItemStand>(); component.m_name = kind.Name; component.m_autoAttach = false; } if ((Object)(object)val2 == (Object)null) { Plugin.Warn(kind.Id + ": " + kind.Source + " has no Container"); Object.DestroyImmediate((Object)(object)val); return null; } val2.m_name = kind.Name; if (!kind.Copy) { val2.m_width = kind.Columns.Value; val2.m_height = kind.RowsNow(kind.Columns.Value); val2.m_privacy = (PrivacySetting)2; } val2.m_defaultItems = new DropTable(); val2.m_autoDestroyEmpty = false; val2.m_destroyedLootPrefab = null; Piece component2 = val.GetComponent<Piece>(); if ((Object)(object)component2 != (Object)null) { component2.m_name = kind.Name; component2.m_description = kind.Name + "_desc"; component2.m_enabled = true; } Plugin.Log(kind.Id + ": made from " + kind.Source); return val; } private static GameObject Find(string name) { if (string.IsNullOrEmpty(name)) { return null; } if ((Object)(object)ZNetScene.instance != (Object)null) { GameObject prefab = ZNetScene.instance.GetPrefab(name); if ((Object)(object)prefab != (Object)null) { return prefab; } } if ((Object)(object)ObjectDB.instance != (Object)null) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(name); if ((Object)(object)itemPrefab != (Object)null) { return itemPrefab; } } if (scenePrefabs == null || !scenePrefabs.TryGetValue(name, out var value)) { return null; } return value; } internal static void Refresh() { //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Expected O, but got Unknown //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Expected O, but got Unknown foreach (Kind copy in Kinds.Copies) { if (!Built.TryGetValue(copy.Id, out var value) || (Object)(object)value == (Object)null || (Object)(object)copy.SourcePiece == (Object)null) { continue; } Piece component = value.GetComponent<Piece>(); if (!((Object)(object)component == (Object)null)) { int times = Kinds.CopyCost.Value; component.m_resources = copy.SourcePiece.m_resources.Where((Requirement q) => q != null && (Object)(object)q.m_resItem != (Object)null).Select((Func<Requirement, Requirement>)((Requirement q) => new Requirement { m_resItem = q.m_resItem, m_amount = Math.Max(1, q.m_amount) * times, m_amountPerLevel = q.m_amountPerLevel, m_recover = q.m_recover })).ToArray(); component.m_craftingStation = copy.SourcePiece.m_craftingStation; component.m_icon = Badged(copy.SourcePiece.m_icon); } } Kind[] all = Kinds.All; foreach (Kind kind in all) { if (!Built.TryGetValue(kind.Id, out var value2) || (Object)(object)value2 == (Object)null) { continue; } Container componentInChildren = value2.GetComponentInChildren<Container>(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.m_width = kind.Columns.Value; componentInChildren.m_height = kind.RowsNow(kind.Columns.Value); } Piece component2 = value2.GetComponent<Piece>(); if ((Object)(object)component2 == (Object)null) { continue; } List<Requirement> list = new List<Requirement>(); foreach (var item3 in Rules.ParseRecipe(kind.Recipe.Value)) { string item = item3.item; int item2 = item3.amount; GameObject obj = Find(item); ItemDrop val = ((obj != null) ? obj.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null) { Plugin.Warn(kind.Id + ": no item " + item + " for the recipe"); continue; } list.Add(new Requirement { m_resItem = val, m_amount = item2, m_recover = true }); } if (list.Count == 0) { GameObject obj2 = Find("Wood"); ItemDrop val2 = ((obj2 != null) ? obj2.GetComponent<ItemDrop>() : null); if ((Object)(object)val2 != (Object)null) { list.Add(new Requirement { m_resItem = val2, m_amount = 10, m_recover = true }); } } component2.m_resources = list.ToArray(); string value3 = kind.Station.Value; object craftingStation; if (!(value3 == "none")) { GameObject obj3 = Find(value3); craftingStation = ((obj3 != null) ? obj3.GetComponent<CraftingStation>() : null); } else { craftingStation = null; } component2.m_craftingStation = (CraftingStation)craftingStation; GameObject obj4 = Find(kind.IconItem); ItemDrop val3 = ((obj4 != null) ? obj4.GetComponent<ItemDrop>() : null); if ((Object)(object)val3 != (Object)null && val3.m_itemData?.m_shared?.m_icons != null && val3.m_itemData.m_shared.m_icons.Length != 0) { component2.m_icon = val3.m_itemData.m_shared.m_icons[0]; } component2.m_icon = Badged(component2.m_icon); } Hammer(); } internal static Sprite Badged(Sprite icon) { //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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_00fb: 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_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Invalid comparison between Unknown and I4 //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0168: 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_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: 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_023d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)icon == (Object)null || ours.Contains(icon)) { return icon; } if (badged.TryGetValue(icon, out var value) && (Object)(object)value != (Object)null) { return value; } if ((int)SystemInfo.graphicsDeviceType == 4) { return icon; } RenderTexture val = null; RenderTexture active = RenderTexture.active; try { Texture2D texture = icon.texture; if ((Object)(object)texture == (Object)null) { return icon; } Rect val2; try { val2 = icon.textureRect; } catch { val2 = icon.rect; } val = (RenderTexture.active = RenderTexture.GetTemporary(128, 128, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2)); GL.Clear(true, true, Color.clear); Graphics.Blit((Texture)(object)texture, val, new Vector2(((Rect)(ref val2)).width / (float)((Texture)texture).width, ((Rect)(ref val2)).height / (float)((Texture)texture).height), new Vector2(((Rect)(ref val2)).x / (float)((Texture)texture).width, ((Rect)(ref val2)).y / (float)((Texture)texture).height)); RenderTexture.active = val; Texture2D val3 = new Texture2D(128, 128, (TextureFormat)4, false) { name = "deep_icon_" + ((Object)icon).name, wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1 }; val3.ReadPixels(new Rect(0f, 0f, 128f, 128f), 0, 0, false); Color32[] pixels = val3.GetPixels32(); byte[] array = new byte[pixels.Length * 4]; for (int i = 0; i < pixels.Length; i++) { Color32 val4 = pixels[i]; array[i * 4] = val4.r; array[i * 4 + 1] = val4.g; array[i * 4 + 2] = val4.b; array[i * 4 + 3] = val4.a; } SlotBadge.Apply(array, 128, bottomUp: true); for (int j = 0; j < pixels.Length; j++) { pixels[j] = new Color32(array[j * 4], array[j * 4 + 1], array[j * 4 + 2], array[j * 4 + 3]); } val3.SetPixels32(pixels); val3.Apply(false, true); Sprite val5 = Sprite.Create(val3, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f), icon.pixelsPerUnit * 128f / Mathf.Max(1f, ((Rect)(ref val2)).width)); ((Object)val5).name = ((Object)val3).name; badged[icon] = val5; ours.Add(val5); return val5; } catch (Exception ex) { Plugin.Warn("icon badge for " + ((Object)icon).name + ": " + ex.Message); badged[icon] = icon; return icon; } finally { RenderTexture.active = active; if ((Object)(object)val != (Object)null) { RenderTexture.ReleaseTemporary(val); } } } internal static void Hammer() { GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("Hammer") : null); PieceTable val2 = ((!((Object)(object)val != (Object)null)) ? null : val.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_buildPieces); if ((Object)(object)val2 == (Object)null) { return; } bool flag = false; foreach (Kind item in Kinds.Every()) { if (Built.TryGetValue(item.Id, out var value) && !((Object)(object)value == (Object)null)) { bool flag2 = item.On; bool flag3 = val2.m_pieces.Contains(value); if (flag2 && !flag3) { val2.m_pieces.Add(value); flag = true; } else if (!flag2 && flag3) { val2.m_pieces.Remove(value); flag = true; } } } if (flag) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { Traverse.Create((object)localPlayer).Method("UpdateAvailablePiecesList", Array.Empty<object>()).GetValue(); } } } } public static class SlotBadge { public const float Share = 0.48f; private static readonly byte[] Fill = new byte[3] { 22, 20, 18 }; private static readonly byte[] Frame = new byte[3] { 214, 176, 104 }; private static readonly byte[] Sign = new byte[3] { 248, 238, 214 }; public static void Apply(byte[] rgba, int size, bool bottomUp) { if (rgba == null || size < 8 || rgba.Length < size * size * 4) { return; } float num = (float)Math.Round((float)size * 0.48f); float num2 = Math.Max(1f, (float)size * 0.02f); float num3 = (float)size - num2 - num / 2f; float num4 = (float)size - num2 - num / 2f; float num5 = num / 2f; float r = num * 0.14f; float num6 = Math.Max(1.5f, num * 0.075f); float num7 = Math.Max(1.5f, num * 0.07f); float a = num * 0.355f; float num8 = Math.Max(1.2f, num * 0.068f); float[] p = Lemniscate(a, num3, num4, 256); int num9 = Math.Max(0, (int)Math.Floor(num3 - num5 - num7 - 1f)); for (int i = Math.Max(0, (int)Math.Floor(num4 - num5 - num7 - 1f)); i < size; i++) { for (int j = num9; j < size; j++) { float num10 = (float)j + 0.5f; float num11 = (float)i + 0.5f; float num12 = RoundBox(num10 - num3, num11 - num4, num5, r); int i2 = ((bottomUp ? (size - 1 - i) : i) * size + j) * 4; if (num12 > 0f) { float num13 = Clamp01(1f - num12 / num7) * 0.55f; if (num13 > 0f) { Blend(rgba, i2, 0, 0, 0, num13); } continue; } float num14 = Clamp01(0f - num12); float num15 = Clamp01(num12 + num6 + 0.5f); float num16 = (num11 - (num4 - num5)) / num; byte r2 = (byte)((float)(int)Fill[0] + 18f * (1f - num16)); byte g = (byte)((float)(int)Fill[1] + 16f * (1f - num16)); byte b = (byte)((float)(int)Fill[2] + 12f * (1f - num16)); Blend(rgba, i2, r2, g, b, 0.95f * num14); if (num15 > 0f) { Blend(rgba, i2, Frame[0], Frame[1], Frame[2], num15 * num14); } if (!(num15 >= 1f)) { float num17 = Nearest(p, num10, num11); float num18 = Clamp01(num8 + 1.6f - num17 + 0.5f) * 0.8f; if (num18 > 0f) { Blend(rgba, i2, 0, 0, 0, num18 * (1f - num15)); } float num19 = Clamp01(num8 - num17 + 0.5f); if (num19 > 0f) { Blend(rgba, i2, Sign[0], Sign[1], Sign[2], num19 * (1f - num15)); } } } } } private static float[] Lemniscate(float a, float cx, float cy, int n) { float[] array = new float[n * 2]; for (int i = 0; i < n; i++) { double num = Math.PI * 2.0 * (double)i / (double)n; double num2 = Math.Sin(num); double num3 = Math.Cos(num); double num4 = 1.0 + num2 * num2; array[i * 2] = (float)((double)cx + (double)a * num3 / num4); array[i * 2 + 1] = (float)((double)cy + (double)a * num2 * num3 / num4 * 1.15); } return array; } private static float Nearest(float[] p, float x, float y) { float num = float.MaxValue; for (int i = 0; i < p.Length; i += 2) { float num2 = p[i] - x; float num3 = p[i + 1] - y; float num4 = num2 * num2 + num3 * num3; if (num4 < num) { num = num4; } } return (float)Math.Sqrt(num); } private static float RoundBox(float x, float y, float half, float r) { float val = Math.Abs(x) - half + r; float num = Math.Abs(y) - half + r; float num2 = Math.Max(val, 0f); float num3 = Math.Max(num, 0f); return (float)Math.Sqrt(num2 * num2 + num3 * num3) + Math.Min(Math.Max(val, num), 0f) - r; } private static float Clamp01(float v) { if (!(v < 0f)) { if (!(v > 1f)) { return v; } return 1f; } return 0f; } private static void Blend(byte[] p, int i, byte r, byte g, byte b, float k) { if (!(k <= 0f)) { if (k > 1f) { k = 1f; } float num = (float)(int)p[i + 3] / 255f; float num2 = k + num * (1f - k); if (!(num2 <= 0f)) { p[i] = (byte)Math.Round(((float)(int)r * k + (float)(int)p[i] * num * (1f - k)) / num2); p[i + 1] = (byte)Math.Round(((float)(int)g * k + (float)(int)p[i + 1] * num * (1f - k)) / num2); p[i + 2] = (byte)Math.Round(((float)(int)b * k + (float)(int)p[i + 2] * num * (1f - k)) / num2); p[i + 3] = (byte)Math.Round(num2 * 255f); } } } } internal static class Trophies { internal sealed class Entry { internal string Prefab; internal string Name; internal Sprite Icon; } private static readonly string[] Order = new string[54] { "TrophyBoar", "TrophyNeck", "TrophyDeer", "TrophyEikthyr", "TrophyGreydwarf", "TrophyGreydwarfBrute", "TrophyGreydwarfShaman", "TrophySkeleton", "TrophyGhost", "TrophyBjorn", "TrophyForestTroll", "TrophyTheElder", "TrophyDraugr", "TrophyDraugrElite", "TrophyLeech", "TrophyBlob", "TrophySkeletonPoison", "TrophySurtling", "TrophyWraith", "TrophyAbomination", "TrophyKvastur", "TrophyBonemass", "TrophySerpent", "TrophyWolf", "TrophyFenring", "TrophyUlv", "TrophyCultist", "TrophyHatchling", "TrophySGolem", "TrophyDragonQueen", "TrophyDeathsquito", "TrophyGoblin", "TrophyGoblinBrute", "TrophyGoblinShaman", "TrophyLox", "TrophyGrowth", "TrophyBjornUndead", "TrophyGoblinKing", "TrophySeeker", "TrophySeekerBrute", "TrophyTick", "TrophyHare", "TrophyGjall", "TrophyDvergr", "TrophySeekerQueen", "TrophyAsksvin", "TrophyVolture", "TrophyCharredMelee", "TrophyCharredArcher", "TrophyCharredMage", "TrophyMorgen", "TrophyBonemawSerpent", "TrophyFallenValkyrie", "TrophyFader" }; internal static readonly List<Entry> List = new List<Entry>(); internal static Dictionary<string, int> Slots; private static ObjectDB builtFor; internal static void Build(bool force = false) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Invalid comparison between Unknown and I4 ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || instance.m_items == null || instance.m_items.Count == 0 || (!force && (Object)(object)builtFor == (Object)(object)instance && List.Count > 0)) { return; } Dictionary<string, Entry> dictionary = new Dictionary<string, Entry>(StringComparer.Ordinal); foreach (GameObject item in instance.m_items) { if (!((Object)(object)item == (Object)null)) { SharedData val = item.GetComponent<ItemDrop>()?.m_itemData?.m_shared; if (val != null && (int)val.m_itemType == 13 && !string.IsNullOrEmpty(val.m_name) && !dictionary.ContainsKey(((Object)item).name)) { dictionary[((Object)item).name] = new Entry { Prefab = ((Object)item).name, Name = val.m_name, Icon = ((val.m_icons != null && val.m_icons.Length != 0) ? val.m_icons[0] : null) }; } } } List<Entry> list = new List<Entry>(); string[] order = Order; foreach (string key in order) { if (dictionary.TryGetValue(key, out var value)) { list.Add(value); dictionary.Remove(key); } } List<Entry> list2 = new List<Entry>(dictionary.Values); list2.Sort((Entry a, Entry b) => string.CompareOrdinal(a.Prefab, b.Prefab)); list.AddRange(list2); Dictionary<string, int> dictionary2 = new Dictionary<string, int>(StringComparer.Ordinal); List.Clear(); foreach (Entry item2 in list) { if (!dictionary2.ContainsKey(item2.Name)) { dictionary2[item2.Name] = List.Count; List.Add(item2); } } Slots = dictionary2; builtFor = instance; Plugin.Log($"trophy chest: {List.Count} kinds of trophies ({list.Count - list2.Count} of the game's order, {list2.Count} others)"); } internal static int Collected(Inventory inventory) { if (Slots == null) { return 0; } HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); foreach (ItemData item in inventory.m_inventory) { if (item.m_stack > 0 && Slots.ContainsKey(item.m_shared.m_name)) { hashSet.Add(item.m_shared.m_name); } } return hashSet.Count; } } internal static class TrophyStand { [HarmonyPatch(typeof(ItemStand), "Interact")] private static class Use { private static bool Prefix(ItemStand __instance, Humanoid user, bool hold, bool alt, ref bool __result) { Container val = Ours(__instance); if ((Object)(object)val == (Object)null) { return true; } if (alt) { if (!hold) { Turn(__instance, val, user); } __result = true; return false; } __result = val.Interact(user, hold, false); return false; } } [HarmonyPatch(typeof(ItemStand), "UseItem")] private static class UseHotbar { private static bool Prefix(ItemStand __instance, ref bool __result) { if ((Object)(object)Ours(__instance) == (Object)null) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(ItemStand), "GetHoverText")] private static class HoverText { private static void Postfix(ItemStand __instance, ref string __result) { Container val = Ours(__instance); if (!((Object)(object)val == (Object)null)) { __result = val.GetHoverText() + Localization.instance.Localize("\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] $deep_change_model"); } } } [HarmonyPatch(typeof(ItemStand), "GetHoverName")] private static class HoverName { private static void Postfix(ItemStand __instance, ref string __result) { Container val = Ours(__instance); if ((Object)(object)val != (Object)null) { __result = val.GetHoverName(); } } } [HarmonyPatch(typeof(ItemStand), "DropItem")] private static class NoDrop { private static bool Prefix(ItemStand __instance) { return (Object)(object)Ours(__instance) == (Object)null; } } internal static Container Ours(ItemStand stand) { if ((Object)(object)stand == (Object)null) { return null; } Container component = ((Component)stand).GetComponent<Container>(); if (!((Object)(object)component != (Object)null) || !(component.m_name == Kinds.Trophy.Name)) { return null; } return component; } private static List<GameObject> Models(Container c) { List<GameObject> list = new List<GameObject>(); ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || c.m_inventory == null) { return list; } List<ItemData> list2 = new List<ItemData>(c.m_inventory.m_inventory); list2.Sort((ItemData a, ItemData b) => (a.m_gridPos.y == b.m_gridPos.y) ? a.m_gridPos.x.CompareTo(b.m_gridPos.x) : a.m_gridPos.y.CompareTo(b.m_gridPos.y)); foreach (ItemData item in list2) { GameObject val = null; foreach (Trophies.Entry item2 in Trophies.List) { if (item2.Name == item.m_shared.m_name) { val = instance.GetItemPrefab(item2.Prefab); break; } } if ((Object)(object)val == (Object)null && (Object)(object)item.m_dropPrefab != (Object)null) { val = instance.GetItemPrefab(((Object)item.m_dropPrefab).name); } if (!((Object)(object)val == (Object)null) && !list.Contains(val) && !((Object)(object)ItemStand.GetAttachPrefab(val) == (Object)null)) { list.Add(val); } } return list; } private static void Turn(ItemStand stand, Container c, Humanoid user) { ZNetView nview = stand.m_nview; if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return; } List<GameObject> list = Models(c); if (list.Count == 0) { if (user != null) { ((Character)user).Message((MessageType)2, "$deep_no_trophies", 0, (Sprite)null, false); } return; } int num = nview.GetZDO().GetInt(ZDOVars.s_item, 0); int num2 = -1; for (int i = 0; i < list.Count; i++) { if (StringExtensionMethods.GetStableHashCode(((Object)list[i]).name) == num) { num2 = i; break; } } int num3 = num2 + 1; if (num3 >= list.Count) { nview.InvokeRPC("RPC_DestroyAttachment", Array.Empty<object>()); if (user != null) { ((Character)user).Message((MessageType)2, "$deep_no_model", 0, (Sprite)null, false); } return; } GameObject val = list[num3]; nview.InvokeRPC(ZNetView.Everybody, "SetVisualItem", new object[4] { StringExtensionMethods.GetStableHashCode(((Object)val).name), 0, 1, 0 }); string text = val.GetComponent<ItemDrop>()?.m_itemData?.m_shared?.m_name; if (text != null && user != null) { ((Character)user).Message((MessageType)2, text, 0, (Sprite)null, false); } } } internal static class Words { private static readonly Action<Localization, string, string> AddWord = AccessTools.MethodDelegate<Action<Localization, string, string>>(AccessTools.Method(typeof(Localization), "AddWord", (Type[])null, (Type[])null), (object)null, true); private static readonly (string key, string en, string ru)[] Texts = new(string, string, string)[10] { ("deep_total", "Total", "Всего"), ("deep_cells", "Cells used", "Занято ячеек"), ("deep_noremove", "Can be dismantled only when empty", "Разобрать можно только пустым"), ("deep_refused", "This storage does not take that item", "Сюда этот предмет не принимают"), ("deep_noroom", "Not enough room", "Не хватает места"), ("deep_trophy_missing", "Not collected yet", "Ещё не добыт"), ("deep_collected", "Kinds collected", "Собрано видов"), ("deep_change_model", "Change trophy", "Сменить трофей"), ("deep_no_trophies", "Put a trophy in first", "Сначала положите трофей"), ("deep_no_model", "No trophy shown", "Без трофея") }; internal static void Add(Localization localization, string language) { if (localization == null || AddWord == null) { return; } bool flag = string.Equals(language, "Russian", StringComparison.OrdinalIgnoreCase); Kind[] all = Kinds.All; foreach (Kind kind in all) { AddWord(localization, kind.Id, flag ? kind.Ru : kind.En); AddWord(localization, kind.Id + "_desc", flag ? kind.DescRu : kind.DescEn); } (string, string, string)[] texts = Texts; for (int i = 0; i < texts.Length; i++) { var (arg, text, text2) = texts[i]; AddWord(localization, arg, flag ? text2 : text); } foreach (Kind copy in Kinds.Copies) { if (!((Object)(object)copy.SourcePiece == (Object)null)) { string text3 = localization.Localize(copy.SourcePiece.m_name); AddWord(localization, copy.Id, Cells.CopyName(text3, flag)); AddWord(localization, copy.Id + "_desc", flag ? ("Копия «" + text3 + "»: столько же ячеек, но в ячейке нет предела стопки (до 1 млрд). Один вид предмета в ячейке, принимает любые предметы.") : ("A copy of the " + text3 + ": as many cells, but a cell has no stack limit (up to 1 billion). One kind of item per cell, takes any item.")); } } } internal static void Refresh() { Localization instance = Localization.instance; if (instance != null) { Add(instance, instance.GetSelectedLanguage()); } } } }