Decompiled source of BUG OreEnrichment v1.1.0
BUG_OreEnrichment.dll
Decompiled 17 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; 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.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Logging; using CommonAPI; using CommonAPI.Systems; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.0.0")] [module: UnverifiableCode] [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 OreEnrichment { public static class Catalysis { public const int IdBase = 10000; public const int MaxSourceId = 1999; public const int TechBase = 1975; public const int Batches = 3; public const int Gain = 4; public const int CellsPerTab = 98; public static readonly int[] Catalysts = new int[5] { 1114, 1120, 1123, 1124, 1127 }; private static readonly string[] TechNames = new string[5] { "Catalysis I", "Catalysis II", "Catalysis III", "Catalysis IV", "Catalysis V" }; private static readonly Dictionary<int, RecipeProto> sources = new Dictionary<int, RecipeProto>(); private static readonly Dictionary<int, Sprite> icons = new Dictionary<int, Sprite>(); private static readonly Dictionary<int, string> badgeOf = new Dictionary<int, string>(); private static readonly List<KeyValuePair<RecipeProto, Func<Sprite>>> marked = new List<KeyValuePair<RecipeProto, Func<Sprite>>>(); private static readonly Dictionary<int, Sprite> badged = new Dictionary<int, Sprite>(); private static readonly Dictionary<RectTransform, List<Image>> overlays = new Dictionary<RectTransform, List<Image>>(); private static readonly Dictionary<RectTransform, RectTransform> layers = new Dictionary<RectTransform, RectTransform>(); public static void Scale(int[] items, int[] counts, int[] resultCounts, int catalyst, out int[] items2, out int[] counts2, out int[] resultCounts2) { items2 = new int[items.Length + 1]; counts2 = new int[items.Length + 1]; for (int i = 0; i < items.Length; i++) { items2[i] = items[i]; counts2[i] = counts[i] * 3; } items2[items.Length] = catalyst; counts2[items.Length] = 1; resultCounts2 = new int[resultCounts.Length]; for (int j = 0; j < resultCounts.Length; j++) { resultCounts2[j] = resultCounts[j] * 4; } } public static bool Reaches(Dictionary<int, HashSet<int>> makes, IEnumerable<int> from, ICollection<int> targets) { HashSet<int> hashSet = new HashSet<int>(); Stack<int> stack = new Stack<int>(from); while (stack.Count > 0) { int num = stack.Pop(); if (!hashSet.Add(num)) { continue; } if (targets.Contains(num)) { return true; } if (!makes.TryGetValue(num, out var value)) { continue; } foreach (int item in value) { stack.Push(item); } } return false; } public static int Stage(int depth, int deepest) { return Math.Max(0, Math.Min(Catalysts.Length - 1, depth * Catalysts.Length / (deepest + 1))); } internal static Sprite IconFor(int sourceId) { if (icons.TryGetValue(sourceId, out var value)) { return value; } sources.TryGetValue(sourceId, out var value2); Dictionary<int, Sprite> dictionary = icons; object obj = ((value2 != null) ? value2.iconSprite : null); if (obj == null) { ItemProto obj2 = ((ProtoSet<ItemProto>)(object)LDB.items).Select((value2 != null) ? value2.Results[0] : 0); obj = ((obj2 != null) ? obj2.iconSprite : null); } Sprite result = (Sprite)obj; dictionary[sourceId] = (Sprite)obj; return result; } internal static void Mark(RecipeProto r, Func<Sprite> picture, string badge) { badgeOf[((Proto)r).ID] = badge; marked.Add(new KeyValuePair<RecipeProto, Func<Sprite>>(r, picture)); } private static void SetSprites(bool withBadge) { foreach (KeyValuePair<RecipeProto, Func<Sprite>> item in marked) { RecipeProto key = item.Key; Sprite val = item.Value(); if (withBadge && (Object)(object)val != (Object)null) { if (!badged.TryGetValue(((Proto)key).ID, out var value)) { value = (badged[((Proto)key).ID] = Plugin.Badged(val, badgeOf[((Proto)key).ID])); } val = value; } Traverse.Create((object)key).Field("_iconSprite").SetValue((object)val); } } [HarmonyPrefix] [HarmonyPatch(typeof(IconSet), "Create")] private static void BeforeAtlas() { SetSprites(withBadge: false); } [HarmonyPostfix] [HarmonyPatch(typeof(IconSet), "Create")] private static void AfterAtlas() { try { SetSprites(withBadge: true); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Badged recipes keep plain pictures: " + ex.Message)); } } private static void DrawBadges(RectTransform grid, RecipeProto[] shown) { //IL_0163: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)grid == (Object)null || shown == null) { return; } if (!overlays.TryGetValue(grid, out var value)) { value = (overlays[grid] = new List<Image>()); } int num = 0; Vector2 val2 = default(Vector2); foreach (RecipeProto val in shown) { if (val != null && badgeOf.TryGetValue(((Proto)val).ID, out var value2)) { if (num == value.Count) { Image component = new GameObject("catalysis-badge", new Type[2] { typeof(RectTransform), typeof(Image) }).GetComponent<Image>(); ((Component)component).transform.SetParent((Transform)(object)grid, false); RectTransform rectTransform = ((Graphic)component).rectTransform; RectTransform rectTransform2 = ((Graphic)component).rectTransform; RectTransform rectTransform3 = ((Graphic)component).rectTransform; ((Vector2)(ref val2))..ctor(0f, 1f); rectTransform3.pivot = val2; Vector2 anchorMin = (rectTransform2.anchorMax = val2); rectTransform.anchorMin = anchorMin; ((Graphic)component).rectTransform.sizeDelta = new Vector2(40f, 40f); ((Graphic)component).raycastTarget = false; value.Add(component); } int num2 = val.GridIndex % 100 - 1; int num3 = val.GridIndex % 1000 / 100 - 1; value[num].sprite = Plugin.Icon(value2); ((Graphic)value[num]).rectTransform.anchoredPosition = new Vector2((float)(num2 * 46 + 3), (float)(-num3 * 46 - 3)); ((Component)value[num]).gameObject.SetActive(true); num++; } } for (int j = num; j < value.Count; j++) { ((Component)value[j]).gameObject.SetActive(false); } } [HarmonyPostfix] [HarmonyPatch(typeof(UIRecipePicker), "RefreshIcons")] private static void PickerBadges(UIRecipePicker __instance, RecipeProto[] ___protoArray) { RawImage iconImage = __instance.iconImage; DrawBadges((iconImage != null) ? ((Graphic)iconImage).rectTransform : null, ___protoArray); } [HarmonyPostfix] [HarmonyPatch(typeof(UIReplicatorWindow), "RefreshRecipeIcons")] private static void ReplicatorBadges(UIReplicatorWindow __instance, RecipeProto[] ___recipeProtoArray) { Image recipeBg = __instance.recipeBg; RectTransform bg = ((recipeBg != null) ? ((Graphic)recipeBg).rectTransform : null); RawImage recipeIcons = __instance.recipeIcons; DrawBadges(Above(bg, (recipeIcons != null) ? ((Component)recipeIcons).transform : null), ___recipeProtoArray); } private static RectTransform Above(RectTransform bg, Transform icons) { //IL_0052: 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_0062: Expected O, but got Unknown //IL_008a: 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_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0125: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)bg == (Object)null || (Object)(object)icons == (Object)null || (Object)(object)icons.parent == (Object)null) { return bg; } if (!layers.TryGetValue(bg, out var value) || (Object)(object)value == (Object)null) { value = (RectTransform)new GameObject("catalysis-badges", new Type[1] { typeof(RectTransform) }).transform; ((Transform)value).SetParent(icons.parent, false); layers[bg] = value; } ((Transform)value).SetSiblingIndex(icons.GetSiblingIndex() + 1); ((Transform)value).localScale = Vector3.one; ((Transform)value).localRotation = Quaternion.identity; if ((Object)(object)((Transform)bg).parent == (Object)(object)((Transform)value).parent) { value.anchorMin = bg.anchorMin; value.anchorMax = bg.anchorMax; value.pivot = bg.pivot; value.sizeDelta = bg.sizeDelta; value.anchoredPosition = bg.anchoredPosition; } else { RectTransform obj = value; RectTransform obj2 = value; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(0.5f, 0.5f); obj2.anchorMax = val; obj.anchorMin = val; value.pivot = bg.pivot; RectTransform obj3 = value; Rect rect = bg.rect; obj3.sizeDelta = ((Rect)(ref rect)).size; ((Transform)value).position = ((Transform)bg).position; } Vector3 localPosition = ((Transform)value).localPosition; ((Transform)value).localPosition = new Vector3(localPosition.x, localPosition.y, 0f); return value; } internal static void Generate(HashSet<int> skip, int[] tabs, float x0, float dx, float y) { //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Invalid comparison between Unknown and I4 //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Invalid comparison between Unknown and I4 //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Invalid comparison between Unknown and I4 //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_06a2: Unknown result type (might be due to invalid IL or missing references) //IL_0476: Unknown result type (might be due to invalid IL or missing references) //IL_047d: Expected O, but got Unknown //IL_04de: Unknown result type (might be due to invalid IL or missing references) //IL_04e3: Unknown result type (might be due to invalid IL or missing references) Dictionary<int, int> techDepth = new Dictionary<int, int>(); Dictionary<int, int> dictionary = new Dictionary<int, int>(); int num = 0; TechProto[] dataArray = ((ProtoSet<TechProto>)(object)LDB.techs).dataArray; foreach (TechProto val in dataArray) { if (val?.UnlockRecipes != null && val.UnlockRecipes.Length != 0 && val.page == 0) { int num2 = Depth(val); num = Math.Max(num, num2); int[] unlockRecipes = val.UnlockRecipes; foreach (int key in unlockRecipes) { dictionary[key] = (dictionary.TryGetValue(key, out var value) ? Math.Min(value, num2) : num2); } } } Dictionary<int, HashSet<int>> makes = new Dictionary<int, HashSet<int>>(); RecipeProto[] dataArray2 = ((ProtoSet<RecipeProto>)(object)LDB.recipes).dataArray; foreach (RecipeProto val2 in dataArray2) { if (val2?.Items != null && val2.Results != null) { int[] unlockRecipes = val2.Items; for (int j = 0; j < unlockRecipes.Length; j++) { Edge(unlockRecipes[j], val2.Results); } } } List<RecipeProto> list = new List<RecipeProto>(); dataArray2 = ((ProtoSet<RecipeProto>)(object)LDB.recipes).dataArray; foreach (RecipeProto val3 in dataArray2) { if (val3 != null && !skip.Contains(((Proto)val3).ID) && ((Proto)val3).ID <= 1999 && val3.GridIndex >= 1101 && !val3.NonProductive && val3.productive && val3.Items != null && val3.Items.Length != 0 && val3.Results != null && val3.Results.Length != 0 && val3.Items.Length + val3.Results.Length + 1 <= 7 && (int)val3.Type != 8 && (int)val3.Type != 6 && (int)val3.Type != 7 && (int)val3.Type != 0) { bool flag = false; int[] unlockRecipes = val3.Results; foreach (int num3 in unlockRecipes) { flag |= ((ProtoSet<ItemProto>)(object)LDB.items).Select(num3)?.CanBuild ?? true; } if (!flag) { list.Add(val3); } } } list.Sort((RecipeProto a, RecipeProto b) => (a.GridIndex == b.GridIndex) ? ((Proto)a).ID.CompareTo(((Proto)b).ID) : a.GridIndex.CompareTo(b.GridIndex)); List<int>[] array = new List<int>[Catalysts.Length]; for (int num4 = 0; num4 < array.Length; num4++) { array[num4] = new List<int>(); } List<RecipeProto> list2 = new List<RecipeProto>(); int num5 = 0; int num6 = 0; int num7 = 0; int num8 = 0; foreach (RecipeProto item2 in list) { int value2; int num9 = Stage(dictionary.TryGetValue(((Proto)item2).ID, out value2) ? value2 : 0, num); int num10 = 0; int num11 = num9; while (num11 >= 0 && num10 == 0) { ItemProto val4 = ((ProtoSet<ItemProto>)(object)LDB.items).Select(Catalysts[num11]); if (val4 != null && val4.GridIndex > 0 && Array.IndexOf(item2.Items, ((Proto)val4).ID) < 0 && Array.IndexOf(item2.Results, ((Proto)val4).ID) < 0) { num10 = ((Proto)val4).ID; } num11--; } if (num10 == 0) { num7++; continue; } Scale(item2.Items, item2.ItemCounts, item2.ResultCounts, num10, out var items, out var counts, out var resultCounts); if (Reaches(makes, item2.Results, items)) { num6++; continue; } if (((ProtoSet<RecipeProto>)(object)LDB.recipes).Exist(10000 + ((Proto)item2).ID)) { num8++; continue; } if (num5 >= tabs.Length * 98) { num8++; continue; } ItemProto obj = ((ProtoSet<ItemProto>)(object)LDB.items).Select(item2.Results[0]); string text = ((obj != null) ? ((Proto)obj).name : null) ?? ""; string name = ((Proto)((ProtoSet<ItemProto>)(object)LDB.items).Select(num10)).name; string name2 = (string.IsNullOrEmpty(((Proto)item2).name) ? text : ((Proto)item2).name) + Lang.T(" (Catalysed)"); RecipeProto val5 = new RecipeProto(); ((Proto)val5).ID = 10000 + ((Proto)item2).ID; ((Proto)val5).Name = name2; val5.Description = Lang.F("{0} {1} from three batches of the inputs and 1 {2}. The normal recipe makes {3} from the same inputs.\nRuns in the same building as the normal recipe.", resultCounts[0], text, name, item2.ResultCounts[0] * 3); val5.Type = item2.Type; val5.Handcraft = false; val5.Explicit = true; val5.TimeSpend = item2.TimeSpend * 4; val5.Items = items; val5.ItemCounts = counts; val5.Results = (int[])item2.Results.Clone(); val5.ResultCounts = resultCounts; val5.GridIndex = tabs[num5 / 98] * 1000 + (num5 % 98 / 14 + 1) * 100 + num5 % 14 + 1; val5.IconPath = "BUGOreEnrichment/cat/" + ((Proto)item2).ID; val5.IconTag = ""; val5.NonProductive = false; RecipeProto val6 = val5; sources[((Proto)item2).ID] = item2; list2.Add(val6); Edge(num10, item2.Results); array[num9].Add(((Proto)val6).ID); num5++; } TechProto[] array2 = (TechProto[])(object)new TechProto[Catalysts.Length]; for (int num12 = 0; num12 < array2.Length; num12++) { ItemProto obj2 = ((ProtoSet<ItemProto>)(object)LDB.items).Select(Catalysts[num12]); string text2 = ((obj2 != null) ? ((Proto)obj2).name : null) ?? "a catalyst"; array2[num12] = Plugin.NewTech(1975 + num12, Lang.T(TechNames[num12]), Lang.F("Catalysed copies of recipes: three batches of the inputs and one catalyst give four batches of the products, in the same building. This stage covers recipes of its research level and uses {0} where the recipe does not already contain it.", text2), "BUGOreEnrichment/tab-cat", (num12 != 0) ? ((Proto)array2[num12 - 1]).ID : 0, Plugin.TechUnlocking(Catalysts[num12]), num12 + 1, array[num12].ToArray(), new Vector2(x0 + (float)num12 * dx, y)); } int num13 = Plugin.Append<RecipeProto>((ProtoSet<RecipeProto>)(object)LDB.recipes, (IList<RecipeProto>)list2); Plugin.Insert(array2); int num14 = 0; for (int num15 = 0; num15 < list2.Count; num15++) { list2[num15].Preload(num13 + num15); if ((Object)(object)list2[num15].iconSprite == (Object)null) { num14++; } } RecipeProto.InitRecipeItems(); foreach (RecipeProto item3 in list2) { int source = ((Proto)item3).ID - 10000; Mark(item3, () => IconFor(source), "badge-cat"); } Plugin.Log.LogInfo((object)("Catalysed copies: " + num5 + " of " + list.Count + " recipes (" + num6 + " would close a loop, " + num7 + " have no free catalyst, " + num8 + " no free id or cell); per stage " + array[0].Count + "/" + array[1].Count + "/" + array[2].Count + "/" + array[3].Count + "/" + array[4].Count + "; " + num14 + " copies without icon")); int Depth(TechProto t) { if (t == null) { return 0; } if (techDepth.TryGetValue(((Proto)t).ID, out var value3)) { return value3; } techDepth[((Proto)t).ID] = 0; int num16 = 0; int[][] array3 = new int[2][] { t.PreTechs, t.PreTechsImplicit }; foreach (int[] array4 in array3) { if (array4 != null) { int[] array5 = array4; foreach (int num17 in array5) { num16 = Math.Max(num16, Depth(((ProtoSet<TechProto>)(object)LDB.techs).Select(num17)) + 1); } } } return techDepth[((Proto)t).ID] = num16; } void Edge(int from, int[] to) { if (!makes.TryGetValue(from, out var value3)) { value3 = (makes[from] = new HashSet<int>()); } foreach (int item in to) { value3.Add(item); } } } } public sealed class Alt { public int Id; public int Type; public int Time; public int Row; public int Col; public int Tech; public int GbType; public int Normal; public int[] In; public int[] InN; public int[] Out; public int[] OutN; public string Name; public string Tier; public string Badge; public bool Handcraft; } public static class Tables { public const int Smelt = 1; public const int Chemical = 2; public const int Refine = 3; public const int Assemble = 4; public const int Particle = 5; public const int Water = 1000; public const int Hydrogen = 1120; public const int Acid = 1116; public const int Oil = 1114; public const int Graphite = 1109; public const int FireIce = 1011; public const int Organic = 1117; public const int Unipolar = 1016; public const int Fractal = 1013; public const int Kimberlite = 1012; public const int Grating = 1014; public const int Spiniform = 1015; public const int Iron = 0; public const int Copper = 1; public const int Stone = 2; public const int Coal = 3; public const int Silicon = 4; public const int Titanium = 5; public const int DustBase = 9451; public const int CrushBase = 9501; public const int WashBase = 9511; public const int EnrichBase = 9521; public static readonly int[] Ores = new int[6] { 1001, 1002, 1005, 1006, 1003, 1004 }; public static readonly string[] OreNames = new string[6] { "Iron", "Copper", "Stone", "Coal", "Silicon", "Titanium" }; public static readonly string[] Icons = new string[6] { "iron-dust", "copper-dust", "stone-dust", "coal-dust", "silicon-dust", "titanium-dust" }; public static readonly int[] TierIn = new int[3] { 4, 4, 4 }; public static readonly int[] TierOut = new int[3] { 6, 8, 12 }; public static readonly string[] TierNames = new string[3] { "Enriched I", "Enriched II", "Enriched III" }; private static readonly string[] ProductNames = new string[9] { "Iron Ingot", "Magnet", "Copper Ingot", "Stone Brick", "Glass", "Energetic Graphite", "High-Purity Silicon", "Titanium Ingot", "Steel" }; public const int GbFurnace = 11; public const int GbPlasmaFurnace = 13; public const int GbPolymer = 16; private static readonly int[][][] Products; public const double WashGain = 1.5; public static int Dust(int ore) { return 9451 + ore; } public static bool Plentiful(int item) { if (item != 1120 && item != 1000) { if (item >= 9451) { return item < 9457; } return false; } return true; } public static string Describe(Alt a, Func<int, string> name) { CultureInfo invariantCulture = CultureInfo.InvariantCulture; if (a.Tech == 0) { return Lang.T((a.In.Length == 1) ? "1 ore gives 1 dust.\nSmelted with an additive, dust gives 1.5, 2 or 3 times what the ore gives in its normal recipe (Ore Enrichment I to III).\nWashing instead of crushing gives 1.5 times as much dust." : "2 ore and 1 water give 3 dust: 1.5 times the dust of crushing.\nThis multiplies with Ore Enrichment: washed dust ends up as 2.25, 3 or 4.5 times what the ore gives in its normal recipe."); } int normal = a.Normal; double num = (double)a.OutN[0] / (double)normal; bool flag = a.In[0] >= 9451 && a.In[0] < 9451 + Ores.Length; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(Lang.F(flag ? "{0} {1} from {2} {3}. The normal recipe makes {4} from the same ore." : "{0} {1} from {2} {3}. The normal recipe makes {4} from the same amount.", a.OutN[0], name(a.Out[0]), a.InN[0], name(a.In[0]), normal)); if (flag) { stringBuilder.Append("\n").Append(Lang.F("Per ore: x{0} with crushed dust, x{1} with washed dust.", num.ToString("0.##", invariantCulture), (num * 1.5).ToString("0.##", invariantCulture))); } for (int i = 1; i < a.In.Length; i++) { stringBuilder.Append("\n").Append(Lang.F((i == 1) ? "{0} {1} per batch" : "{0} {1} as well", a.InN[i], name(a.In[i]))).Append((i == a.In.Length - 1) ? Lang.F(": the batch gives {0} more than without.", a.OutN[0] - normal) : ","); } return stringBuilder.ToString(); } public static List<Alt> All() { List<Alt> list = new List<Alt>(); for (int i = 0; i < Ores.Length; i++) { list.Add(new Alt { Id = 9501 + i, Type = 4, Time = 30, Row = 1, Col = i + 1, Tech = 0, Handcraft = true, Name = OreNames[i] + " Ore Crushing", In = new int[1] { Ores[i] }, InN = new int[1] { 1 }, Out = new int[1] { Dust(i) }, OutN = new int[1] { 1 } }); list.Add(new Alt { Id = 9511 + i, Type = 2, Time = 90, Row = 2, Col = i + 1, Tech = 0, Name = OreNames[i] + " Ore Washing", In = new int[2] { Ores[i], 1000 }, InN = new int[2] { 2, 1 }, Out = new int[1] { Dust(i) }, OutN = new int[1] { 3 } }); } for (int j = 0; j < Products.Length; j++) { for (int k = 0; k < 3; k++) { int[] array = Products[j][0]; int[] obj = Products[j][k + 1]; List<int> list2 = new List<int> { array[1] }; List<int> list3 = new List<int> { array[2] * TierIn[k] }; int[] array2 = obj; foreach (int item in array2) { list2.Add(item); list3.Add((k != 0 || !Plentiful(item)) ? 1 : 2); } list.Add(new Alt { Id = 9521 + j * 3 + k, Type = Products[j][4][k], GbType = Products[j][5][k], Time = array[3] * TierOut[k], Row = 3 + k, Col = j + 1, Tech = k + 1, Name = ProductNames[j] + " (" + TierNames[k] + ")", Tier = TierNames[k], Normal = TierIn[k], In = list2.ToArray(), InN = list3.ToArray(), Out = new int[1] { array[0] }, OutN = new int[1] { TierOut[k] } }); } } return list; } static Tables() { int[][][] array = new int[9][][]; int[][] array2 = new int[6][]; int[] obj = new int[4] { 1101, 0, 1, 60 }; obj[1] = Dust(0); array2[0] = obj; array2[1] = new int[1] { 1120 }; array2[2] = new int[2] { 1120, Dust(2) }; array2[3] = new int[1] { 1011 }; array2[4] = new int[3] { 1, 1, 1 }; array2[5] = new int[3] { 0, 11, 13 }; array[0] = array2; int[][] array3 = new int[6][]; int[] obj2 = new int[4] { 1102, 0, 1, 90 }; obj2[1] = Dust(0); array3[0] = obj2; array3[1] = new int[1] { Dust(3) }; array3[2] = new int[1] { 1120 }; array3[3] = new int[1] { 1016 }; array3[4] = new int[3] { 1, 1, 5 }; array3[5] = new int[3] { 0, 11, 0 }; array[1] = array3; int[][] array4 = new int[6][]; int[] obj3 = new int[4] { 1104, 0, 1, 60 }; obj3[1] = Dust(1); array4[0] = obj3; array4[1] = new int[1] { 1116 }; array4[2] = new int[2] { 1116, Dust(0) }; array4[3] = new int[1] { 1117 }; array4[4] = new int[3] { 2, 2, 2 }; array4[5] = new int[3] { 0, 0, 16 }; array[2] = array4; int[][] array5 = new int[6][]; int[] obj4 = new int[4] { 1108, 0, 1, 60 }; obj4[1] = Dust(2); array5[0] = obj4; array5[1] = new int[1] { Dust(3) }; array5[2] = new int[1] { 1000 }; array5[3] = new int[1] { 1116 }; array5[4] = new int[3] { 1, 4, 2 }; array5[5] = new int[3]; array[3] = array5; int[][] array6 = new int[6][]; int[] obj5 = new int[4] { 1110, 0, 2, 120 }; obj5[1] = Dust(2); array6[0] = obj5; array6[1] = new int[1] { Dust(4) }; array6[2] = new int[1] { 1116 }; array6[3] = new int[1] { 1013 }; array6[4] = new int[3] { 1, 2, 1 }; array6[5] = new int[3] { 0, 0, 11 }; array[4] = array6; int[][] array7 = new int[6][]; int[] obj6 = new int[4] { 1109, 0, 2, 120 }; obj6[1] = Dust(3); array7[0] = obj6; array7[1] = new int[1] { 1120 }; array7[2] = new int[1] { 1114 }; array7[3] = new int[1] { 1011 }; array7[4] = new int[3] { 1, 3, 2 }; array7[5] = new int[3] { 0, 0, 16 }; array[5] = array7; int[][] array8 = new int[6][]; int[] obj7 = new int[4] { 1105, 0, 2, 120 }; obj7[1] = Dust(4); array8[0] = obj7; array8[1] = new int[1] { Dust(3) }; array8[2] = new int[1] { 1109 }; array8[3] = new int[2] { 1120, 1014 }; array8[4] = new int[3] { 1, 1, 2 }; array8[5] = new int[3] { 11, 11, 0 }; array[6] = array8; int[][] array9 = new int[6][]; int[] obj8 = new int[4] { 1106, 0, 2, 120 }; obj8[1] = Dust(5); array9[0] = obj8; array9[1] = new int[1] { 1116 }; array9[2] = new int[2] { 1116, Dust(3) }; array9[3] = new int[2] { 1120, 1015 }; array9[4] = new int[3] { 2, 2, 1 }; array9[5] = new int[3] { 0, 0, 13 }; array[7] = array9; array[8] = new int[6][] { new int[4] { 1103, 1101, 3, 180 }, new int[1] { Dust(3) }, new int[1] { 1109 }, new int[1] { 1012 }, new int[3] { 1, 1, 1 }, new int[3] { 0, 11, 13 } }; Products = array; } } [BepInPlugin("bug.dsp.oreenrichment", "BUG_OreEnrichment", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [CommonAPISubmoduleDependency(new string[] { "ProtoRegistry", "TabSystem" })] public class Plugin : BaseUnityPlugin { public const string Guid = "bug.dsp.oreenrichment"; public const string IconRoot = "BUGOreEnrichment/"; public const int TechBase = 1971; internal static ManualLogSource Log; private static readonly List<RecipeProto> recipes = new List<RecipeProto>(); private static readonly List<Alt> alts = Tables.All(); private static bool techsBuilt; private static readonly string[] PreciousItemDescs = new string[5] { "Left at the anode when copper is refined electrolytically. Leached, it gives gold and silver dust.", "Gold recovered from anode slime. Goes into circuit boards, processors and power buildings, or is smelted into ingots.", "Silver recovered from anode slime. Goes into coils and power buildings, or is smelted into ingots.", "Smelted gold. Doubles the products of electronics recipes, and with gold dust triples them.", "Smelted silver. Doubles the products of coil and chip recipes, and saves material in power buildings." }; private static readonly Dictionary<string, Sprite> icons = new Dictionary<string, Sprite>(); private static int tabIndex; private static int preciousTab; private static int preciousTab2; private static int recycleTab; private static int[] catalysisTabs = new int[0]; private static readonly string[] TechNames = new string[4] { "Ore Crushing", "Ore Enrichment I", "Ore Enrichment II", "Ore Enrichment III" }; private static readonly string[] TechDescs = new string[4] { "Crush ores into dust in an assembler, or wash them with water in a chemical plant: three dust from two ore.", "Smelt dust with a simple additive such as hydrogen or coal dust: one and a half times the products of the ore.", "Smelt dust with stronger additives such as sulfuric acid or graphite: twice the products of the ore.", "Smelt dust with a rare-vein additive such as fire ice or unipolar magnets: three times the products of the ore." }; private static readonly int[] GateItems = new int[4] { 2306, 1120, 1116, 2104 }; private static readonly HashSet<int> normals = new HashSet<int>(); internal static float RowGap = 4f; private static float rowX; private static float rowDx; private static float rowY; private void Awake() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Expected O, but got Unknown //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Expected O, but got Unknown //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Expected O, but got Unknown //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Harmony val = new Harmony("bug.dsp.oreenrichment"); val.PatchAll(typeof(Plugin)); val.PatchAll(typeof(Catalysis)); val.PatchAll(typeof(TabLayout)); TabLayout.Own = () => new int[4] { tabIndex, preciousTab, preciousTab2, recycleTab }.Concat(catalysisTabs); Lang.Current = ((BaseUnityPlugin)this).Config.Bind<Language>("General", "Language", Language.English, "Language of the mod's own texts: English, Chinese or Turkish (applies after restarting the game). Item and building names follow the game's language.").Value; using (ProtoRegistry.StartModLoad("bug.dsp.oreenrichment")) { int num = (tabIndex = TabSystem.RegisterTab("bug.dsp.oreenrichment:tab", new TabData(Lang.T("Enrichment"), "BUGOreEnrichment/tab"))); catalysisTabs = new int[2] { TabSystem.RegisterTab("bug.dsp.oreenrichment:cat1", new TabData(Lang.T("Catalysis"), "BUGOreEnrichment/tab-cat")), TabSystem.RegisterTab("bug.dsp.oreenrichment:cat2", new TabData(Lang.T("Catalysis II"), "BUGOreEnrichment/tab-cat")) }; for (int num2 = 0; num2 < Tables.Ores.Length; num2++) { ProtoRegistry.RegisterItem(Tables.Dust(num2), Lang.F("{0} Dust", Lang.T(Tables.OreNames[num2])), Lang.F("Crushed {0} ore: 1 per ore from crushing, 3 per 2 ore from washing. Smelted with an additive it gives 1.5, 2 or 3 times what the ore gives in its normal recipe (Ore Enrichment I to III).", Lang.T(Tables.OreNames[num2])), "BUGOreEnrichment/" + Tables.Icons[num2], ProtoRegistry.GetGridIndex(num, num2 + 1, 1), 100, (EItemType)2).Productive = true; } preciousTab = TabSystem.RegisterTab("bug.dsp.oreenrichment:precious", new TabData("Au-Ag", "BUGOreEnrichment/tab-precious")); preciousTab2 = TabSystem.RegisterTab("bug.dsp.oreenrichment:precious2", new TabData("Au-Ag II", "BUGOreEnrichment/tab-precious")); recycleTab = TabSystem.RegisterTab("bug.dsp.oreenrichment:recycle", new TabData(Lang.T("Recycling"), "BUGOreEnrichment/tab-recycle")); for (int num3 = 0; num3 < Precious.Items.Length; num3++) { ProtoRegistry.RegisterItem(Precious.Items[num3], Lang.T(Precious.ItemNames[num3]), Lang.T(PreciousItemDescs[num3]), "BUGOreEnrichment/" + Precious.ItemIcons[num3], ProtoRegistry.GetGridIndex(preciousTab, num3 + 1, 1), 100, (EItemType)2).Productive = true; } foreach (Alt alt in alts) { RecipeProto val2 = ProtoRegistry.RegisterRecipe(alt.Id, (ERecipeType)(byte)alt.Type, alt.Time, alt.In, alt.InN, alt.Out, alt.OutN, "", 0, ProtoRegistry.GetGridIndex(num, alt.Col, alt.Row), (alt.Tech > 0) ? alt.Name : Lang.F((alt.In.Length == 1) ? "{0} Ore Crushing" : "{0} Ore Washing", Lang.T(Tables.OreNames[alt.Col - 1])), ""); val2.Handcraft = alt.Handcraft; val2.Explicit = true; recipes.Add(val2); } } } internal static Sprite Icon(string name) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if (icons.TryGetValue(name, out var value)) { return value; } using (Stream stream = typeof(Plugin).Assembly.GetManifestResourceStream(name + ".png")) { if (stream != null) { byte[] array = new byte[stream.Length]; stream.Read(array, 0, array.Length); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true); ImageConversion.LoadImage(val, array); value = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); } } return icons[name] = value; } internal static Sprite Badged(Sprite icon, string badge) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //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) Sprite val = Icon(badge); if ((Object)(object)icon == (Object)null || (Object)(object)val == (Object)null) { return icon; } RenderTexture temporary = RenderTexture.GetTemporary(80, 80, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2); RenderTexture active = RenderTexture.active; Graphics.Blit((Texture)(object)icon.texture, temporary); RenderTexture.active = temporary; Texture2D val2 = new Texture2D(80, 80, (TextureFormat)4, true); val2.ReadPixels(new Rect(0f, 0f, 80f, 80f), 0, 0); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); Color32[] pixels = val2.GetPixels32(); Color32[] pixels2 = val.texture.GetPixels32(); if (pixels2.Length != pixels.Length) { return icon; } for (int i = 0; i < pixels.Length; i++) { int a = pixels2[i].a; if (a != 0) { pixels[i] = new Color32((byte)((pixels2[i].r * a + pixels[i].r * (255 - a)) / 255), (byte)((pixels2[i].g * a + pixels[i].g * (255 - a)) / 255), (byte)((pixels2[i].b * a + pixels[i].b * (255 - a)) / 255), (byte)Math.Max(a, pixels[i].a)); } } val2.SetPixels32(pixels); val2.Apply(true); return Sprite.Create(val2, new Rect(0f, 0f, 80f, 80f), new Vector2(0.5f, 0.5f)); } private static void SetIcons() { for (int i = 0; i < recipes.Count; i++) { Alt alt = alts[i]; string text = ((alt.Tech > 0) ? ("badge-" + alt.Tech) : ((alt.In.Length > 1) ? "badge-wash" : null)); if (text != null) { ItemProto obj = ((ProtoSet<ItemProto>)(object)LDB.items).Select(alt.Out[0]); Sprite val = Badged((obj != null) ? obj.iconSprite : null, text); if ((Object)(object)val != (Object)null) { Traverse.Create((object)recipes[i]).Field("_iconSprite").SetValue((object)val); } } } } [HarmonyPrefix] [HarmonyPatch(typeof(Resources), "Load", new Type[] { typeof(string), typeof(Type) })] private static bool LoadIcon(string path, ref Object __result) { if (path == null || !path.StartsWith("BUGOreEnrichment/")) { return true; } string text = path.Substring("BUGOreEnrichment/".Length); __result = (Object)(object)((text.StartsWith("cat/") && int.TryParse(text.Substring(4), out var result)) ? Catalysis.IconFor(result) : ((text.StartsWith("pv/") && int.TryParse(text.Substring(3), out var result2)) ? Precious.IconFor(result2) : Icon(text))); return false; } [HarmonyPostfix] [HarmonyPatch(typeof(UIRecipePicker), "_OnOpen")] [HarmonyAfter(new string[] { "dsp.common-api.CommonAPI" })] private static void FilterTab(UIRecipePicker __instance) { //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) try { Traverse val = Traverse.Create((object)__instance); int value = val.Field<int>("currentType").Value; MethodInfo methodInfo = AccessTools.Method(typeof(UIRecipePicker), "OnTypeButtonClick", (Type[])null, (Type[])null); Dictionary<int, bool> dictionary = new Dictionary<int, bool> { { tabIndex, false }, { preciousTab, false }, { preciousTab2, false }, { recycleTab, false } }; int[] array = catalysisTabs; foreach (int key in array) { dictionary[key] = false; } foreach (int item in new List<int>(dictionary.Keys)) { methodInfo.Invoke(__instance, new object[1] { item }); RecipeProto[] value2 = val.Field<RecipeProto[]>("protoArray").Value; foreach (RecipeProto val2 in value2) { dictionary[item] |= val2 != null; } } methodInfo.Invoke(__instance, new object[1] { (dictionary.TryGetValue(value, out var value3) && !value3) ? 1 : value }); UITabButton[] componentsInChildren = ((Component)__instance.pickerTrans).GetComponentsInChildren<UITabButton>(true); foreach (UITabButton val3 in componentsInChildren) { int value4 = Traverse.Create((object)val3).Field<int>("tabIndex").Value; int num = 0; foreach (KeyValuePair<int, bool> item2 in dictionary) { if (!item2.Value && item2.Key < value4) { num++; } } if (dictionary.TryGetValue(value4, out var value5)) { ((Component)val3).gameObject.SetActive(value5); } ((RectTransform)((Component)val3).transform).anchoredPosition = new Vector2((float)(70 * (value4 - num) - 54), -75f); } } catch (Exception ex) { Log.LogWarning((object)("Tab filter skipped: " + ex.Message)); } } [HarmonyPostfix] [HarmonyPatch(typeof(VFPreload), "InvokeOnLoadWorkEnded")] [HarmonyAfter(new string[] { "me.xiaoye97.plugin.Dyson.LDBTool", "dsp.common-api.CommonAPI", "org.LoShin.GenesisBook", "bug.dsp.deliveryitemchain", "bug.dsp.dronecoverage" })] private static void Register() { //IL_0111: Unknown result type (might be due to invalid IL or missing references) if (techsBuilt) { return; } techsBuilt = true; try { Adapt(); } catch (Exception ex) { Log.LogError((object)("Recipes keep the vanilla ratios: " + ex)); } try { BuildTechs(); } catch (Exception ex2) { Log.LogError((object)("Research not added, the recipes cannot be unlocked: " + ex2)); } try { SetIcons(); } catch (Exception ex3) { Log.LogWarning((object)("Recipe icons keep the product's picture: " + ex3.Message)); } try { Precious.Generate(preciousTab, preciousTab2, tabIndex, rowX, rowDx, rowY - 2f * RowGap, 1971, 1972); } catch (Exception ex4) { Log.LogError((object)("Gold and silver recipes not added: " + ex4)); } try { Recycling.Generate(new Vector2(rowX + (float)Precious.TechNames.Length * rowDx, rowY - 2f * RowGap), 1971); Recycling.GenerateLevels(recycleTab, rowX, rowDx, rowY - 3f * RowGap, RowGap); } catch (Exception ex5) { Log.LogError((object)("Dark Fog recycling recipes not added: " + ex5)); } try { HashSet<int> hashSet = new HashSet<int>(normals); foreach (Alt alt in alts) { hashSet.Add(alt.Id); } Catalysis.Generate(hashSet, catalysisTabs, rowX, rowDx, rowY - RowGap); } catch (Exception ex6) { Log.LogError((object)("Catalysed recipes not added: " + ex6)); } try { Precious.RefreshItemRecipes(); } catch (Exception ex7) { Log.LogWarning((object)("Item tooltips do not list the new recipes: " + ex7.Message)); } } private static void Adapt() { HashSet<int> hashSet = new HashSet<int>(); foreach (Alt alt3 in alts) { hashSet.Add(alt3.Id); } int num = 0; int num2 = 0; for (int i = 0; i < alts.Count; i++) { Alt alt = alts[i]; if (alt.Tech == 0) { continue; } int num3 = ((alt.In[0] >= 9451 && alt.In[0] < 9451 + Tables.Ores.Length) ? Tables.Ores[alt.In[0] - 9451] : alt.In[0]); RecipeProto val = null; RecipeProto[] dataArray = ((ProtoSet<RecipeProto>)(object)LDB.recipes).dataArray; foreach (RecipeProto val2 in dataArray) { if (val2 != null && !hashSet.Contains(((Proto)val2).ID) && val2.Items.Length == 1 && val2.Items[0] == num3 && val2.Results.Length == 1 && val2.Results[0] == alt.Out[0]) { val = val2; break; } } RecipeProto val3 = recipes[i]; if (val == null) { val3.GridIndex = 0; alt.Row = 0; num2++; continue; } int num4 = Tables.TierIn[alt.Tech - 1] * val.ItemCounts[0]; int num5 = Tables.TierOut[alt.Tech - 1] * val.ResultCounts[0]; int num6 = val.TimeSpend * Tables.TierOut[alt.Tech - 1]; if (num4 != alt.InN[0] || num5 != alt.OutN[0] || num6 != alt.Time) { num++; } normals.Add(((Proto)val).ID); alt.Normal = Tables.TierIn[alt.Tech - 1] * val.ResultCounts[0]; alt.Time = (val3.TimeSpend = num6); val3.ItemCounts[0] = (alt.InN[0] = num4); val3.ResultCounts[0] = (alt.OutN[0] = num5); } Dictionary<int, int> dictionary = new Dictionary<int, int>(); for (int k = 0; k < alts.Count; k++) { Alt alt2 = alts[k]; if (alt2.Tech != 0 && alt2.Row != 0) { if (!dictionary.TryGetValue(alt2.Out[0], out var value)) { value = (dictionary[alt2.Out[0]] = dictionary.Count + 1); } alt2.Col = value; recipes[k].GridIndex = ProtoRegistry.GetGridIndex(tabIndex, value, alt2.Row); } } if (num + num2 > 0) { Log.LogInfo((object)(num + " recipes follow a changed normal recipe, " + num2 + " hidden: their product has no normal recipe here")); } } private static void BuildTechs() { //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Expected I4, but got Unknown //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) TechProtoSet techs = LDB.techs; foreach (RecipeProto recipe in recipes) { if (((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(((Proto)recipe).ID) != recipe) { throw new InvalidOperationException("recipe " + ((Proto)recipe).ID + " was not added (id taken?)"); } } Layout(((ProtoSet<TechProto>)(object)techs).dataArray, out var x, out var dx, out var y); rowX = x; rowDx = dx; rowY = y; TechProto[] array = (TechProto[])(object)new TechProto[TechNames.Length]; for (int i = 0; i < array.Length; i++) { List<int> list = new List<int>(); foreach (Alt alt in alts) { if (alt.Tech == i && alt.Row > 0) { list.Add(alt.Id); } } array[i] = NewTech(1971 + i, Lang.T(TechNames[i]), Lang.T(TechDescs[i]), "BUGOreEnrichment/" + ((i == 0) ? Tables.Icons[0] : "tab"), (i != 0) ? ((Proto)array[i - 1]).ID : 0, TechUnlocking(GateItems[i]), i + 1, list.ToArray(), new Vector2(x + (float)i * dx, y)); } Insert(array); HashSet<int> hashSet = new HashSet<int>(); ItemProto[] dataArray = ((ProtoSet<ItemProto>)(object)LDB.items).dataArray; foreach (ItemProto val in dataArray) { if (val?.prefabDesc != null && val.prefabDesc.isAssembler) { hashSet.Add((int)val.prefabDesc.assemblerRecipeType); } } int num = 0; for (int k = 0; k < recipes.Count; k++) { RecipeProto val2 = recipes[k]; if (alts[k].GbType != 0 && hashSet.Contains(alts[k].GbType)) { val2.Type = (ERecipeType)(byte)alts[k].GbType; num++; } val2.preTech = array[alts[k].Tech]; if (alts[k].Tech > 0) { ItemProto obj = ((ProtoSet<ItemProto>)(object)LDB.items).Select(val2.Results[0]); ((Proto)val2).name = ((obj != null) ? ((Proto)obj).name : null) + " (" + Lang.T(alts[k].Tier) + ")"; } val2.description = Tables.Describe(alts[k], delegate(int id) { ItemProto obj2 = ((ProtoSet<ItemProto>)(object)LDB.items).Select(id); return ((obj2 != null) ? ((Proto)obj2).name : null) ?? ("#" + id); }); } Log.LogInfo((object)(num + " recipes moved to other mods' building types; added " + recipes.Count + " recipes and " + array.Length + " techs (ids " + ((Proto)array[0]).ID + "-" + ((Proto)array[^1]).ID + ") at x " + x + " y " + y)); } internal static TechProto NewTech(int id, string name, string desc, string icon, int after, int gate, int cubes, int[] unlocks, Vector2 position) { //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Expected O, but got Unknown //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) if (((ProtoSet<TechProto>)(object)LDB.techs).Exist(id)) { throw new InvalidOperationException("tech id " + id + " is taken by another mod"); } int[] array = new int[cubes]; int[] array2 = new int[cubes]; for (int i = 0; i < cubes; i++) { array[i] = TechProto.matrixIds[i]; array2[i] = 10; } long hashNeeded = 36000L << cubes - 1; bool isLabTech = true; TechProto val = ((gate > 0) ? ((ProtoSet<TechProto>)(object)LDB.techs).Select(gate) : null); if (val?.Items != null && val.Items.Length != 0 && val.ItemPoints != null && val.ItemPoints.Length == val.Items.Length && val.HashNeeded > 0 && !SameItems(val.Items, array)) { array = (int[])val.Items.Clone(); array2 = (int[])val.ItemPoints.Clone(); hashNeeded = val.HashNeeded; isLabTech = val.IsLabTech; } TechProto val2 = new TechProto(); ((Proto)val2).ID = id; ((Proto)val2).Name = name; val2.Desc = desc; val2.Conclusion = ""; val2.Published = true; val2.IsLabTech = isLabTech; val2.IconPath = icon; val2.IconTag = ""; val2.PreTechs = ((after == 0) ? new int[0] : new int[1] { after }); val2.PreTechsImplicit = ((gate <= 0) ? new int[0] : new int[1] { gate }); val2.PreItem = new int[0]; val2.Items = array; val2.ItemPoints = array2; val2.HashNeeded = hashNeeded; val2.UnlockRecipes = unlocks; val2.UnlockFunctions = new int[0]; val2.UnlockValues = new double[0]; val2.AddItems = new int[0]; val2.AddItemCounts = new int[0]; val2.PropertyOverrideItems = new int[0]; val2.PropertyItemCounts = new int[0]; val2.PropertyOverrideItemArray = (IDCNT[])(object)new IDCNT[0]; val2.Position = position; return val2; } internal static int Append<T>(ProtoSet<T> set, IList<T> add) where T : Proto { T[] dataArray = set.dataArray; ((ProtoTable)set).Init(dataArray.Length + add.Count); Array.Copy(dataArray, set.dataArray, dataArray.Length); for (int i = 0; i < add.Count; i++) { set.dataArray[dataArray.Length + i] = add[i]; } Dictionary<int, int> dictionary = new Dictionary<int, int>(); for (int j = 0; j < set.dataArray.Length; j++) { dictionary[((Proto)set.dataArray[j]).ID] = j; } Traverse.Create((object)set).Field("dataIndices").SetValue((object)dictionary); if (add.Count > 0 && (object)set.Select(((Proto)add[0]).ID) != (object)add[0]) { throw new InvalidOperationException("proto index not rebuilt"); } return dataArray.Length; } private static bool SameItems(int[] theirs, int[] ours) { foreach (int value in theirs) { if (Array.IndexOf(TechProto.matrixIds, value) < 0) { return false; } } return true; } internal static void Insert(TechProto[] techs) { Plugin.Append<TechProto>((ProtoSet<TechProto>)(object)LDB.techs, (IList<TechProto>)techs); TechProto[] array = techs; for (int i = 0; i < array.Length; i++) { array[i].Preload(); } array = techs; for (int i = 0; i < array.Length; i++) { array[i].Preload2(); } } internal static int TechUnlocking(int item) { HashSet<int> hashSet = new HashSet<int>(); RecipeProto[] dataArray = ((ProtoSet<RecipeProto>)(object)LDB.recipes).dataArray; foreach (RecipeProto val in dataArray) { if (val?.Results != null && Array.IndexOf(val.Results, item) >= 0) { hashSet.Add(((Proto)val).ID); } } TechProto[] dataArray2 = ((ProtoSet<TechProto>)(object)LDB.techs).dataArray; foreach (TechProto val2 in dataArray2) { if (val2?.UnlockRecipes == null) { continue; } int[] unlockRecipes = val2.UnlockRecipes; foreach (int item2 in unlockRecipes) { if (hashSet.Contains(item2)) { return ((Proto)val2).ID; } } } return 0; } public static void Layout(TechProto[] techs, out float x0, out float dx, out float y0) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_0074: 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_0097: 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) float num = float.MaxValue; Dictionary<float, float> dictionary = new Dictionary<float, float>(); SortedSet<float> sortedSet = new SortedSet<float>(); SortedSet<float> sortedSet2 = new SortedSet<float>(); foreach (TechProto val in techs) { if (val != null && val.page == 0 && val.Published) { Vector2 position = val.Position; num = Math.Min(num, position.y); sortedSet.Add(position.y); sortedSet2.Add(position.x); dictionary[position.y] = (dictionary.TryGetValue(position.y, out var value) ? Math.Min(value, position.x) : position.x); } } dx = CommonGap(sortedSet2, 4f); float num2 = (RowGap = CommonGap(sortedSet, 4f)); x0 = Mode(dictionary.Values, 0f); y0 = ((num == float.MaxValue) ? 0f : num) - num2; } private static float CommonGap(SortedSet<float> values, float fallback) { List<float> list = new List<float>(); float num = float.NaN; foreach (float value in values) { if (!float.IsNaN(num) && value - num > 0.5f) { list.Add(value - num); } num = value; } return Mode(list, fallback); } private static float Mode(IEnumerable<float> values, float fallback) { Dictionary<float, int> dictionary = new Dictionary<float, int>(); float num = fallback; int num2 = 0; foreach (float value2 in values) { dictionary[value2] = ((!dictionary.TryGetValue(value2, out var value)) ? 1 : (value + 1)); if (dictionary[value2] > num2 || (dictionary[value2] == num2 && value2 < num)) { num2 = dictionary[value2]; num = value2; } } return num; } } public enum Language { English, Chinese, Turkish } public static class Lang { public static Language Current = Language.English; private static readonly Dictionary<string, string[]> texts = new Dictionary<string, string[]> { ["Iron"] = new string[2] { "铁", "Demir" }, ["Copper"] = new string[2] { "铜", "Bakır" }, ["Stone"] = new string[2] { "石", "Taş" }, ["Coal"] = new string[2] { "煤", "Kömür" }, ["Silicon"] = new string[2] { "硅", "Silisyum" }, ["Titanium"] = new string[2] { "钛", "Titanyum" }, ["{0} Dust"] = new string[2] { "{0}粉", "{0} Tozu" }, ["{0} Ore Crushing"] = new string[2] { "{0}矿粉碎", "{0} Cevheri Öğütme" }, ["{0} Ore Washing"] = new string[2] { "{0}矿水洗", "{0} Cevheri Yıkama" }, ["Crushed {0} ore: 1 per ore from crushing, 3 per 2 ore from washing. Smelted with an additive it gives 1.5, 2 or 3 times what the ore gives in its normal recipe (Ore Enrichment I to III)."] = new string[2] { "粉碎的{0}矿:粉碎每 1 矿得 1 粉,水洗每 2 矿得 3 粉。加入添加剂冶炼时,产量为该矿普通配方的 1.5、2 或 3 倍(矿物富集 I 至 III)。", "Öğütülmüş {0} cevheri: öğütmede cevher başına 1, yıkamada 2 cevherden 3 toz. Katkı maddesiyle eritildiğinde cevherin normal tarifinin 1.5, 2 veya 3 katını verir (Cevher Zenginleştirme I-III)." }, ["Enriched I"] = new string[2] { "富集 I", "Zenginleştirilmiş I" }, ["Enriched II"] = new string[2] { "富集 II", "Zenginleştirilmiş II" }, ["Enriched III"] = new string[2] { "富集 III", "Zenginleştirilmiş III" }, ["Enrichment"] = new string[2] { "富集", "Zenginleştirme" }, ["Catalysis"] = new string[2] { "催化", "Kataliz" }, ["Catalysis II"] = new string[2] { "催化 II", "Kataliz II" }, [" (Catalysed)"] = new string[2] { "(催化)", " (Katalizli)" }, ["Ore Crushing"] = new string[2] { "矿物粉碎", "Cevher Öğütme" }, ["Ore Enrichment I"] = new string[2] { "矿物富集 I", "Cevher Zenginleştirme I" }, ["Ore Enrichment II"] = new string[2] { "矿物富集 II", "Cevher Zenginleştirme II" }, ["Ore Enrichment III"] = new string[2] { "矿物富集 III", "Cevher Zenginleştirme III" }, ["Catalysis I"] = new string[2] { "催化 I", "Kataliz I" }, ["Catalysis III"] = new string[2] { "催化 III", "Kataliz III" }, ["Catalysis IV"] = new string[2] { "催化 IV", "Kataliz IV" }, ["Catalysis V"] = new string[2] { "催化 V", "Kataliz V" }, ["Crush ores into dust in an assembler, or wash them with water in a chemical plant: three dust from two ore."] = new string[2] { "在制造台中把矿石粉碎成矿粉,或在化工厂中用水冲洗:每两份矿石得三份矿粉。", "Cevherleri montaj makinesinde toza öğüt ya da kimya tesisinde suyla yıka: iki cevherden üç toz." }, ["Smelt dust with a simple additive such as hydrogen or coal dust: one and a half times the products of the ore."] = new string[2] { "用氢、煤粉等简单添加剂冶炼矿粉:产量为矿石的 1.5 倍。", "Tozu hidrojen veya kömür tozu gibi basit bir katkıyla erit: cevherin verdiğinin bir buçuk katı ürün." }, ["Smelt dust with stronger additives such as sulfuric acid or graphite: twice the products of the ore."] = new string[2] { "用硫酸、石墨等更强的添加剂冶炼矿粉:产量为矿石的 2 倍。", "Tozu sülfürik asit veya grafit gibi daha güçlü katkılarla erit: cevherin verdiğinin iki katı ürün." }, ["Smelt dust with a rare-vein additive such as fire ice or unipolar magnets: three times the products of the ore."] = new string[2] { "用可燃冰、单极磁石等珍奇矿物添加剂冶炼矿粉:产量为矿石的 3 倍。", "Tozu yanan buz veya tek kutuplu mıknatıs gibi nadir damar katkılarıyla erit: cevherin verdiğinin üç katı ürün." }, ["Catalysed copies of recipes: three batches of the inputs and one catalyst give four batches of the products, in the same building. This stage covers recipes of its research level and uses {0} where the recipe does not already contain it."] = new string[2] { "配方的催化版本:三批原料加一份催化剂产出四批产物,使用同一种建筑。本阶段覆盖对应研究层级的配方,在配方本身不含{0}时以其作为催化剂。", "Tariflerin katalizli kopyaları: üç parti girdi ve bir katalizör, aynı binada dört parti ürün verir. Bu kademe kendi araştırma seviyesindeki tarifleri kapsar ve tarif zaten içermiyorsa {0} kullanır." }, ["1 ore gives 1 dust.\nSmelted with an additive, dust gives 1.5, 2 or 3 times what the ore gives in its normal recipe (Ore Enrichment I to III).\nWashing instead of crushing gives 1.5 times as much dust."] = new string[2] { "1 份矿石得 1 份矿粉。\n加入添加剂冶炼时,矿粉的产量为矿石普通配方的 1.5、2 或 3 倍(矿物富集 I 至 III)。\n改用水洗可得 1.5 倍的矿粉。", "1 cevher 1 toz verir.\nKatkı maddesiyle eritilen toz, cevherin normal tarifinin 1.5, 2 veya 3 katını verir (Cevher Zenginleştirme I-III).\nÖğütmek yerine yıkamak 1.5 kat toz verir." }, ["2 ore and 1 water give 3 dust: 1.5 times the dust of crushing.\nThis multiplies with Ore Enrichment: washed dust ends up as 2.25, 3 or 4.5 times what the ore gives in its normal recipe."] = new string[2] { "2 份矿石加 1 份水得 3 份矿粉:是粉碎的 1.5 倍。\n这与矿物富集相乘:水洗矿粉最终为矿石普通配方的 2.25、3 或 4.5 倍。", "2 cevher ve 1 su 3 toz verir: öğütmenin 1.5 katı.\nBu, Cevher Zenginleştirme ile çarpılır: yıkanmış toz, cevherin normal tarifinin 2.25, 3 veya 4.5 katına ulaşır." }, ["{0} {1} from {2} {3}. The normal recipe makes {4} from the same ore."] = new string[2] { "{2} 份{3}产出 {0} 份{1}。同样的矿石用普通配方只得 {4} 份。", "{2} {3} ile {0} {1}. Normal tarif aynı cevherden {4} üretir." }, ["{0} {1} from {2} {3}. The normal recipe makes {4} from the same amount."] = new string[2] { "{2} 份{3}产出 {0} 份{1}。同样的数量用普通配方只得 {4} 份。", "{2} {3} ile {0} {1}. Normal tarif aynı miktardan {4} üretir." }, ["Per ore: x{0} with crushed dust, x{1} with washed dust."] = new string[2] { "按矿石计:粉碎矿粉 x{0},水洗矿粉 x{1}。", "Cevher başına: öğütülmüş tozla x{0}, yıkanmış tozla x{1}." }, ["{0} {1} per batch"] = new string[2] { "每批 {0} 份{1}", "Parti başına {0} {1}" }, ["{0} {1} as well"] = new string[2] { "另加 {0} 份{1}", "ayrıca {0} {1}" }, [": the batch gives {0} more than without."] = new string[2] { ":每批比不加时多 {0} 份。", ": parti, katkısız hale göre {0} fazla verir." }, ["{0} {1} from three batches of the inputs and 1 {2}. The normal recipe makes {3} from the same inputs.\nRuns in the same building as the normal recipe."] = new string[2] { "三批原料加 1 份{2}产出 {0} 份{1}。同样的原料用普通配方只得 {3} 份。\n与普通配方使用同一种建筑。", "Üç parti girdi ve 1 {2} ile {0} {1}. Normal tarif aynı girdilerden {3} üretir.\nNormal tarifle aynı binada çalışır." }, ["Anode Slime"] = new string[2] { "阳极泥", "Anot Çamuru" }, ["Gold Dust"] = new string[2] { "金粉", "Altın Tozu" }, ["Silver Dust"] = new string[2] { "银粉", "Gümüş Tozu" }, ["Gold Ingot"] = new string[2] { "金锭", "Altın Külçe" }, ["Silver Ingot"] = new string[2] { "银锭", "Gümüş Külçe" }, ["Left at the anode when copper is refined electrolytically. Leached, it gives gold and silver dust."] = new string[2] { "铜电解精炼时留在阳极的残渣。浸出后得到金粉和银粉。", "Bakır elektrolizle arıtılırken anotta kalan tortu. Liç edilince altın ve gümüş tozu verir." }, ["Gold recovered from anode slime. Goes into circuit boards, processors and power buildings, or is smelted into ingots."] = new string[2] { "从阳极泥中回收的金。可用于电路板、处理器和电力建筑,或冶炼成锭。", "Anot çamurundan kazanılan altın. Devre kartı, işlemci ve enerji binalarında kullanılır ya da külçeye eritilir." }, ["Silver recovered from anode slime. Goes into coils and power buildings, or is smelted into ingots."] = new string[2] { "从阳极泥中回收的银。可用于线圈和电力建筑,或冶炼成锭。", "Anot çamurundan kazanılan gümüş. Bobinlerde ve enerji binalarında kullanılır ya da külçeye eritilir." }, ["Smelted gold. Doubles the products of electronics recipes, and with gold dust triples them."] = new string[2] { "冶炼后的金。使电子配方产量翻倍,与金粉同用则为三倍。", "Eritilmiş altın. Elektronik tariflerinin ürününü iki katına, altın tozuyla birlikte üç katına çıkarır." }, ["Smelted silver. Doubles the products of coil and chip recipes, and saves material in power buildings."] = new string[2] { "冶炼后的银。使线圈和芯片配方产量翻倍,并节省电力建筑的材料。", "Eritilmiş gümüş. Bobin ve çip tariflerinin ürününü iki katına çıkarır, enerji binalarında malzeme tasarrufu sağlar." }, ["Precious Metal Recovery"] = new string[2] { "贵金属回收", "Değerli Metal Kazanımı" }, ["Gold and Silver Electronics"] = new string[2] { "金银电子", "Altın ve Gümüş Elektronik" }, ["Gold and Silver Construction"] = new string[2] { "金银建造", "Altın ve Gümüş İnşaat" }, ["Fluid Chemistry"] = new string[2] { "流体化学", "Akışkan Kimyası" }, ["Refine copper electrolytically: the anode slime it leaves holds gold and silver. Leach the slime with sulfuric acid and smelt the dust into ingots."] = new string[2] { "电解精炼铜:留下的阳极泥含有金和银。用硫酸浸出阳极泥,再把金属粉冶炼成锭。", "Bakırı elektrolizle arıt: geride kalan anot çamuru altın ve gümüş içerir. Çamuru sülfürik asitle liç et, tozu külçeye erit." }, ["Gold and silver in electronic parts and in everything made with them: parts give up to three times the products, other components twice."] = new string[2] { "在电子零件及所有用它们制造的物品中加入金银:零件产量最高为 3 倍,其他组件为 2 倍。", "Elektronik parçalarda ve onlarla yapılan her şeyde altın ve gümüş: parçalar üç katına kadar, diğer bileşenler iki kat ürün verir." }, ["Gold contacts and silver wiring in buildings, turrets and factories: two batches of the normal materials and a few ingots give three buildings."] = new string[2] { "建筑、炮塔和工厂中的金触点和银导线:两批普通材料加少量金属锭可造出三座建筑。", "Binalarda, taretlerde ve fabrikalarda altın kontak ve gümüş kablo: iki parti normal malzeme ve birkaç külçe üç bina verir." }, ["GenesisBook fluids: nitric acid and hydrochloric acid for gold and silver, oxygen, ammonia, lye and carbon dioxide in dust smelting, and seawater washing that also gives salt."] = new string[2] { "创世之书的流体:硝酸和盐酸用于提炼金银,氧气、氨、烧碱和二氧化碳用于矿粉冶炼,海水冲洗还能得到盐。", "GenesisBook akışkanları: altın ve gümüş için nitrik ve hidroklorik asit, toz eritmede oksijen, amonyak, kostik ve karbondioksit, ayrıca tuz da veren deniz suyuyla yıkama." }, ["Electrolytic Copper Refining"] = new string[2] { "铜电解精炼", "Elektrolitik Bakır Arıtma" }, ["Anode Slime Leaching"] = new string[2] { "阳极泥浸出", "Anot Çamuru Liçi" }, ["Gold Smelting"] = new string[2] { "金冶炼", "Altın Eritme" }, ["Silver Smelting"] = new string[2] { "银冶炼", "Gümüş Eritme" }, ["Nitric Acid Parting"] = new string[2] { "硝酸分金", "Nitrik Asitle Ayrıştırma" }, ["Wohlwill Gold Refining"] = new string[2] { "沃威尔金精炼", "Wohlwill Altın Arıtma" }, ["{0} Ore Seawater Washing"] = new string[2] { "{0}矿海水冲洗", "{0} Cevheri Deniz Suyuyla Yıkama" }, ["Copper dust refined in sulfuric acid gives as much copper as smelting, and anode slime besides."] = new string[2] { "在硫酸中精炼铜粉,得到的铜与冶炼相同,另得阳极泥。", "Sülfürik asitte arıtılan bakır tozu, eritmeyle aynı miktarda bakır ve ayrıca anot çamuru verir." }, ["Sulfuric acid dissolves the copper left in the slime; gold and silver stay behind as dust."] = new string[2] { "硫酸溶解阳极泥中残留的铜,金和银以粉末形式留下。", "Sülfürik asit çamurdaki bakırı çözer; altın ve gümüş toz olarak geride kalır." }, ["Gold dust smelted into ingots."] = new string[2] { "把金粉冶炼成锭。", "Altın tozu külçeye eritilir." }, ["Silver dust smelted into ingots."] = new string[2] { "把银粉冶炼成锭。", "Gümüş tozu külçeye eritilir." }, ["Nitric acid parts silver from gold: more of both from the same slime than sulfuric acid gives."] = new string[2] { "硝酸把银从金中分离:同样的阳极泥得到的金银都比硫酸多。", "Nitrik asit gümüşü altından ayırır: aynı çamurdan sülfürik asitten daha fazla altın ve gümüş." }, ["Gold dust refined by electrolysis in hydrochloric acid: three ingots from two dust."] = new string[2] { "在盐酸中电解精炼金粉:两份金粉得三块金锭。", "Altın tozu hidroklorik asitte elektrolizle arıtılır: iki tozdan üç külçe." }, ["Washing with seawater gives as much dust as washing with water, and salt besides."] = new string[2] { "用海水冲洗得到的矿粉与用水冲洗相同,另得盐。", "Deniz suyuyla yıkama, suyla yıkama kadar toz ve ayrıca tuz verir." }, [" (Dust)"] = new string[2] { "(金属粉)", " (Toz)" }, [" (Ingot)"] = new string[2] { "(金属锭)", " (Külçe)" }, [" (Dust and Ingot)"] = new string[2] { "(粉与锭)", " (Toz ve Külçe)" }, [" (Gold)"] = new string[2] { "(金)", " (Altın)" }, [" (Silver)"] = new string[2] { "(银)", " (Gümüş)" }, [" (Gold and Silver)"] = new string[2] { "(金银)", " (Altın ve Gümüş)" }, [" (Fluid)"] = new string[2] { "(流体)", " (Akışkan)" }, [" and "] = new string[2] { "和", " ve " }, ["{0} Recycling: {1} {2}"] = new string[2] { "{0}回收:{1} {2}", "{0} Geri Dönüşümü: {1} {2}" }, ["Dark Fog Recycling: {0} {1}"] = new string[2] { "黑雾回收:{0} {1}", "Kara Sis Geri Dönüşümü: {0} {1}" }, ["Turns {0} into {1}, in the building that makes them; each recipe is worth about as much as its drops."] = new string[2] { "在制造它们的建筑里把{0}转化为{1};每个配方的价值与所用掉落物大致相当。", "{0} ögesini, onları üreten binada {1} ürünlerine çevirir; her tarifin değeri harcadığı ganimete yakındır." }, ["Turns Dark Fog drops into finished items worth about as much as the drops; the harder the item, the more drops it takes."] = new string[2] { "把黑雾掉落物转化为价值大致相当的成品;物品越难制造,需要的掉落物越多。", "Kara Sis ganimetini değeri ganimete yakın hazır ürünlere çevirir; ürün ne kadar zorsa o kadar çok ganimet ister." }, ["Magazines"] = new string[2] { "弹箱", "Şarjörler" }, ["Shells"] = new string[2] { "炮弹组", "Top mermileri" }, ["Plasma Capsules"] = new string[2] { "等离子胶囊", "Plazma kapsülleri" }, ["Missiles"] = new string[2] { "导弹组", "Füzeler" }, ["Jamming Capsules"] = new string[2] { "干扰胶囊", "Karıştırma kapsülleri" }, ["Explosive Units"] = new string[2] { "爆破单元", "Patlayıcı birimler" }, ["Recycling"] = new string[2] { "回收", "Geri Dönüşüm" }, ["Dark Fog Recycling"] = new string[2] { "黑雾回收", "Kara Sis Geri Dönüşümü" }, ["Opens the research that turns Dark Fog drops into ammunition, matrices, fuel rods, Dyson sphere parts, combat units and buildings."] = new string[2] { "开启把黑雾掉落物转化为弹药、矩阵、燃料棒、戴森球部件、战斗单位和建筑的研究。", "Kara Sis ganimetini mühimmata, matrislere, yakıt çubuklarına, Dyson küresi parçalarına, savaş birimlerine ve binalara çeviren araştırmaları açar." }, ["Matrices"] = new string[2] { "矩阵", "Matrisler" }, ["Fuel Rods"] = new string[2] { "燃料棒", "Yakıt çubukları" }, ["Dyson Sphere"] = new string[2] { "戴森球", "Dyson küresi" }, ["Combat Units"] = new string[2] { "战斗单位", "Savaş birimleri" }, ["Power Facilities"] = new string[2] { "发电设施", "Enerji tesisleri" }, ["Advanced Buildings"] = new string[2] { "高级建筑", "Gelişmiş binalar" }, ["{0} {1} from {2} batches of the normal inputs and {3}. The normal recipe makes {4} from the same inputs."] = new string[2] { "{2} 批普通原料加{3}产出 {0} 份{1}。同样的原料用普通配方只得 {4} 份。", "{2} parti normal girdi ve {3} ile {0} {1}. Normal tarif aynı girdilerden {4} üretir." }, ["Each extra unit gives {0} more {1}."] = new string[2] { "每份额外材料多得 {0} 份{1}。", "Her ek birim {0} {1} daha verir." } }; public static IEnumerable<KeyValuePair<string, string[]>> All => texts; public static string T(string english) { if (Current == Language.English || !texts.TryGetValue(english, out var value)) { return english; } return value[(int)(Current - 1)]; } public static string F(string english, params object[] args) { return string.Format(CultureInfo.InvariantCulture, T(english), args); } } public sealed class Variant { public int Id; public int Product; public int Ore; public int Dust; public int BatchesIn; public int BatchesOut; public int Type; public int[] Extra; public int[] ExtraN; public int Per; public int Tab; public int Row; public int Col; public int Tech; public string Badge; public string Suffix; } public static class Precious { public const int Slime = 9457; public const int GoldDust = 9458; public const int SilverDust = 9459; public const int GoldIngot = 9460; public const int SilverIngot = 9461; public static readonly int[] Items = new int[5] { 9457, 9458, 9459, 9460, 9461 }; public static readonly string[] ItemNames = new string[5] { "Anode Slime", "Gold Dust", "Silver Dust", "Gold Ingot", "Silver Ingot" }; public static readonly string[] ItemIcons = new string[5] { "anode-slime", "gold-dust", "silver-dust", "gold-ingot", "silver-ingot" }; public const int ChainBase = 9601; public const int VariantBase = 9620; public const int TechBase = 1980; public const int RuleBase = 7000; public const int Oxygen = 7019; public const int CO2 = 6206; public const int HCl = 7014; public const int Ammonia = 7002; public const int NaOH = 7020; public const int Seawater = 7018; public const int Nitric = 7017; public const int Salt = 7101; public static readonly string[] TechNames = new string[4] { "Precious Metal Recovery", "Gold and Silver Electronics", "Gold and Silver Construction", "Fluid Chemistry" }; private static readonly int[,] Components = new int[10, 2] { { 1202, 9461 }, { 1301, 9460 }, { 1302, 9461 }, { 1303, 9460 }, { 1205, 9461 }, { 1404, 9460 }, { 1305, 9460 }, { 7803, 9460 }, { 7805, 9460 }, { 7806, 9460 } }; public static readonly int[] ComponentOut = new int[3] { 6, 8, 12 }; public const int ComponentIn = 4; public const int ComponentPer = 6; public const int BuildingIn = 2; public const int BuildingPer = 10; public static readonly int[] GoldParts = new int[11] { 1301, 1302, 1303, 1305, 1402, 1404, 7803, 7805, 7806, 5201, 5202 }; public static readonly int[] SilverParts = new int[7] { 1202, 1203, 1204, 1205, 1206, 1401, 1403 }; public const int MaxIcons = 7; public const int FluidIn = 4; public const int FluidOut = 10; public const int FluidAmount = 2; private static readonly Dictionary<int, int> plain = new Dictionary<int, int>(); private static readonly Dictionary<int, RecipeProto> copied = new Dictionary<int, RecipeProto>(); private static readonly string[] TechDescs = new string[4] { "Refine copper electrolytically: the anode slime it leaves holds gold and silver. Leach the slime with sulfuric acid and smelt the dust into ingots.", "Gold and silver in electronic parts and in everything made with them: parts give up to three times the products, other components twice.", "Gold contacts and silver wiring in buildings, turrets and factories: two batches of the normal materials and a few ingots give three buildings.", "GenesisBook fluids: nitric acid and hydrochloric acid for gold and silver, oxygen, ammonia, lye and carbon dioxide in dust smelting, and seawater washing that also gives salt." }; public static List<Alt> Chain() { int num = Tables.Dust(1); List<Alt> list = new List<Alt>(); list.Add(new Alt { Id = 9601, Type = 2, Time = 240, Row = 1, Col = 1, Name = "Electrolytic Copper Refining", In = new int[2] { num, 1116 }, InN = new int[2] { 4, 1 }, Out = new int[2] { 9457, 1104 }, OutN = new int[2] { 2, 4 } }); list.Add(new Alt { Id = 9602, Type = 2, Time = 180, Row = 1, Col = 2, Name = "Anode Slime Leaching", In = new int[2] { 9457, 1116 }, InN = new int[2] { 2, 1 }, Out = new int[2] { 9458, 9459 }, OutN = new int[2] { 1, 2 } }); list.Add(new Alt { Id = 9603, Type = 1, Time = 90, Row = 1, Col = 3, Name = "Gold Smelting", In = new int[1] { 9458 }, InN = new int[1] { 1 }, Out = new int[1] { 9460 }, OutN = new int[1] { 1 } }); list.Add(new Alt { Id = 9604, Type = 1, Time = 90, Row = 1, Col = 4, Name = "Silver Smelting", In = new int[1] { 9459 }, InN = new int[1] { 1 }, Out = new int[1] { 9461 }, OutN = new int[1] { 1 } }); list.Add(new Alt { Id = 9605, Type = 2, Time = 180, Row = 1, Col = 5, Tech = 3, Name = "Nitric Acid Parting", Badge = "badge-fluid", In = new int[2] { 9457, 7017 }, InN = new int[2] { 2, 1 }, Out = new int[2] { 9458, 9459 }, OutN = new int[2] { 2, 3 } }); list.Add(new Alt { Id = 9606, Type = 2, Time = 180, Row = 1, Col = 6, Tech = 3, Name = "Wohlwill Gold Refining", Badge = "badge-fluid", In = new int[2] { 9458, 7014 }, InN = new int[2] { 2, 1 }, Out = new int[1] { 9460 }, OutN = new int[1] { 3 } }); List<Alt> list2 = list; for (int i = 0; i < Tables.Ores.Length; i++) { list2.Add(new Alt { Id = 9607 + i, Type = 2, Time = 180, Row = 7, Col = i + 1, Tech = 3, Name = Tables.OreNames[i] + " Ore Seawater Washing", Badge = "badge-sea", In = new int[2] { Tables.Ores[i], 7018 }, InN = new int[2] { 4, 2 }, Out = new int[2] { Tables.Dust(i), 7101 }, OutN = new int[2] { 6, 1 } }); } return list2; } public static bool OnEnrichmentTab(Alt a) { return a.Row == 7; } public static bool IsCore(int product) { for (int i = 0; i < Components.GetLength(0); i++) { if (Components[i, 0] == product) { return true; } } return false; } public static Variant Rule(int recipeId, int product, int[] items, bool building, int results = 1) { if (recipeId < 1 || recipeId > 1999 || items == null || IsCore(product) || Array.IndexOf(Items, product) >= 0) { return null; } bool flag = false; bool flag2 = false; foreach (int value in items) { flag |= Array.IndexOf(GoldParts, value) >= 0; flag2 |= Array.IndexOf(SilverParts, value) >= 0; } if (!flag && !flag2) { return null; } if (items.Length + results + 1 > 7) { return null; } if (flag && flag2 && items.Length + results + 2 > 7) { flag2 = false; } bool flag3 = flag && flag2; int[] array = ((!flag3) ? new int[1] { flag ? 9460 : 9461 } : new int[2] { 9460, 9461 }); return new Variant { Id = 7000 + recipeId, Product = product, Extra = array, ExtraN = new int[array.Length], BatchesIn = (building ? 2 : 4), BatchesOut = ((!building) ? (flag3 ? 10 : 8) : (flag3 ? 4 : 3)), Per = (building ? 10 : 6), Tech = ((!building) ? 1 : 2), Badge = (flag3 ? "badge-auag" : (flag ? "badge-au2" : "badge-ag2")), Suffix = (flag3 ? " (Gold and Silver)" : (flag ? " (Gold)" : " (Silver)")) }; } private static int DustOf(int ingot) { if (ingot != 9460) { return 9459; } return 9458; } private static string Metal(int ingot) { if (ingot != 9460) { return "ag"; } return "au"; } public static List<Variant> Variants() { List<Variant> list = new List<Variant>(); int num = 9620; for (int i = 0; i < Components.GetLength(0); i++) { int product = Components[i, 0]; int num2 = Components[i, 1]; int num3 = DustOf(num2); int[][] array = new int[3][] { new int[1] { num3 }, new int[1] { num2 }, new int[2] { num3, num2 } }; for (int j = 0; j < 3; j++) { list.Add(new Variant { Id = num++, Product = product, BatchesIn = 4, BatchesOut = ComponentOut[j], Extra = array[j], ExtraN = new int[array[j].Length], Per = 6, Row = 2 + j, Col = i + 1, Tech = 1, Badge = "badge-" + Metal(num2) + (j + 1), Suffix = (new string[3] { " (Dust)", " (Ingot)", " (Dust and Ingot)" })[j] }); } } int[][] obj = new int[6][] { new int[5] { 1103, 1101, 0, 7019, 1 }, null, null, null, null, null }; int[] obj2 = new int[5] { 1104, 0, 0, 7002, 2 }; obj2[1] = Tables.Ores[1]; obj2[2] = Tables.Dust(1); obj[1] = obj2; int[] obj3 = new int[5] { 1106, 0, 0, 7014, 2 }; obj3[1] = Tables.Ores[5]; obj3[2] = Tables.Dust(5); obj[2] = obj3; int[] obj4 = new int[5] { 1105, 0, 0, 7014, 2 }; obj4[1] = Tables.Ores[4]; obj4[2] = Tables.Dust(4); obj[3] = obj4; int[] obj5 = new int[5] { 1110, 0, 0, 7020, 1 }; obj5[1] = Tables.Ores[2]; obj5[2] = Tables.Dust(2); obj[4] = obj5; int[] obj6 = new int[5] { 1108, 0, 0, 6206, 4 }; obj6[1] = Tables.Ores[2]; obj6[2] = Tables.Dust(2); obj[5] = obj6; int[][] array2 = obj; for (int k = 0; k < array2.Length; k++) { list.Add(new Variant { Id = num++, Product = array2[k][0], Ore = array2[k][1], Dust = array2[k][2], BatchesIn = 4, BatchesOut = 10, Type = array2[k][4], Extra = new int[1] { array2[k][3] }, ExtraN = new int[1] { 2 }, Tab = 1, Row = 6, Col = k + 1, Tech = 3, Badge = "badge-fluid", Suffix = " (Fluid)" }); } return list; } public static int Amount(int inputUnits, int per) { return Math.Max(1, (inputUnits + per / 2) / per); } public static bool Make(Variant v, int[] items, int[] counts, int[] results, int[] resultCounts, out int[] items2, out int[] counts2, out int[] results2, out int[] resultCounts2) { items2 = (counts2 = (results2 = (resultCounts2 = null))); if (items == null || items.Length == 0 || results == null || results.Length == 0 || results[0] != v.Product) { return false; } List<int> list = new List<int>(); List<int> list2 = new List<int>(); int num = 0; for (int i = 0; i < items.Length; i++) { int item = ((v.Dust != 0 && items[i] == v.Ore) ? v.Dust : items[i]); list.Add(item); list2.Add(counts[i] * v.BatchesIn); num += counts[i] * v.BatchesIn; } for (int j = 0; j < v.Extra.Length; j++) { if (list.Contains(v.Extra[j]) || Array.IndexOf(results, v.Extra[j]) >= 0) { return false; } list.Add(v.Extra[j]); list2.Add((v.ExtraN[j] > 0) ? v.ExtraN[j] : Amount(num, v.Per)); } items2 = list.ToArray(); counts2 = list2.ToArray(); results2 = (int[])results.Clone(); resultCounts2 = new int[resultCounts.Length]; for (int k = 0; k < resultCounts.Length; k++) { resultCounts2[k] = resultCounts[k] * v.BatchesOut; } return true; } internal static Sprite IconFor(int recipeId) { object obj; if (!plain.TryGetValue(recipeId, out var value)) { obj = null; } else { ItemProto obj2 = ((ProtoSet<ItemProto>)(object)LDB.items).Select(value); obj = ((obj2 != null) ? obj2.iconSprite : null); } Sprite val = (Sprite)obj; if ((Object)(object)val == (Object)null && copied.TryGetValue(recipeId, out var value2)) { val = value2.iconSprite; } return val; } private static RecipeProto Normal(Variant v, HashSet<int> mine) { RecipeProto val = null; RecipeProto[] dataArray = ((ProtoSet<RecipeProto>)(object)LDB.recipes).dataArray; foreach (RecipeProto val2 in dataArray) { if (val2?.Results == null || val2.Items == null || val2.Results.Length == 0 || val2.Results[0] != v.Product || mine.Contains(((Proto)val2).ID) || ((Proto)val2).ID >= 10000 || (((Proto)val2).ID >= 9501 && ((Proto)val2).ID < 9701)) { continue; } bool num; if (v.Ore == 0) { num = val2.GridIndex < 1101; } else { if (val2.Items.Length != 1) { continue; } num = val2.Items[0] != v.Ore; } if (!num && (val == null || ((Proto)val2).ID < ((Proto)val).ID)) { val = val2; } } return val; } internal static HashSet<int> Generate(int preciousTab, int moreTab, int enrichTab, float x0, float dx, float y, int afterCrushing, int afterEnrichment) { //IL_059b: Unknown result type (might be due to invalid IL or missing references) //IL_05a1: Invalid comparison between Unknown and I4 //IL_05a8: Unknown result type (might be due to invalid IL or missing references) //IL_05ae: Invalid comparison between Unknown and I4 //IL_05b2: Unknown result type (might be due to invalid IL or missing references) //IL_05b8: Invalid comparison between Unknown and I4 //IL_07be: Unknown result type (might be due to invalid IL or missing references) //IL_05bc: Unknown result type (might be due to invalid IL or missing references) HashSet<int> hashSet = new HashSet<int>(); List<RecipeProto> made = new List<RecipeProto>(); List<Alt> list = Chain(); List<Variant> list2 = Variants(); foreach (Alt item6 in list) { hashSet.Add(item6.Id); } foreach (Variant item7 in list2) { hashSet.Add(item7.Id); } List<int>[] unlocks = new List<int>[TechNames.Length]; for (int i = 0; i < unlocks.Length; i++) { unlocks[i] = new List<int>(); } Dictionary<int, HashSet<int>> makes = new Dictionary<int, HashSet<int>>(); RecipeProto[] dataArray = ((ProtoSet<RecipeProto>)(object)LDB.recipes).dataArray; foreach (RecipeProto val in dataArray) { if (val?.Items != null && val.Results != null) { Edge(val.Items, val.Results); } } int missing = 0; int taken = 0; int loops = 0; int noRoom = 0; Dictionary<string, Dictionary<int, int>> cols = new Dictionary<string, Dictionary<int, int>>(); foreach (Alt item8 in list) { bool flag = true; int[] array = item8.In; foreach (int item in array) { flag &= Exists(item); } array = item8.Out; foreach (int item2 in array) { flag &= Exists(item2); } if (!flag) { missing++; continue; } if (((ProtoSet<RecipeProto>)(object)LDB.recipes).Exist(item8.Id)) { taken++; continue; } bool flag2 = OnEnrichmentTab(item8); int num = Column(flag2 ? "wash" : "chain", item8.Id); string name = (flag2 ? Lang.F("{0} Ore Seawater Washing", Lang.T(Tables.OreNames[item8.Id - 9601 - 6])) : Lang.T(item8.Name)); RecipeProto val2 = New(item8.Id, name, item8.Type, item8.Time, item8.In, item8.InN, item8.Out, item8.OutN, (flag2 ? enrichTab : preciousTab) * 1000 + item8.Row * 100 + num); val2.Description = Lang.T(Describe(item8.Id)); val2.Handcraft = item8.Type == 1 && item8.In.Length == 1 && (((ProtoSet<RecipeProto>)(object)LDB.recipes).Select(3)?.Handcraft ?? false); Edge(item8.In, item8.Out); if (item8.Badge != null) { Mark(val2, item8.Out[0], item8.Badge); } made.Add(val2); unlocks[item8.Tech].Add(((Proto)val2).ID); } foreach (Variant v in list2) { bool flag3 = Exists(v.Product); int[] array = v.Extra; foreach (int item3 in array) { flag3 &= Exists(item3); } RecipeProto normal = (flag3 ? Normal(v, hashSet) : null); int tab = ((v.Tab == 1) ? enrichTab : preciousTab); Add(v, normal, () => tab * 1000 + v.Row * 100 + Column(v.Tab + ":" + ((v.Row >= 2 && v.Row <= 4) ? 2 : v.Row), v.Product)); } List<int> cells = new List<int>(); for (int num2 = 5; num2 <= 7; num2++) { for (int num3 = 1; num3 <= 14; num3++) { cells.Add(preciousTab * 1000 + num2 * 100 + num3); } } for (int num4 = 1; num4 <= 7; num4++) { for (int num5 = 1; num5 <= 14; num5++) { cells.Add(moreTab * 1000 + num4 * 100 + num5); } } List<KeyValuePair<RecipeProto, Variant>> list3 = new List<KeyValuePair<RecipeProto, Variant>>(); dataArray = ((ProtoSet<RecipeProto>)(object)LDB.recipes).dataArray; foreach (RecipeProto val3 in dataArray) { if (val3?.Items == null || val3.Results == null || val3.Results.Length == 0 || val3.GridIndex < 1101 || hashSet.Contains(((Proto)val3).ID)) { continue; } int num6 = val3.GridIndex % 1000 / 100; if (num6 < 1 || num6 > 8 || val3.GridIndex % 100 == 0 || (int)val3.Type == 8 || (int)val3.Type == 6 || (int)val3.Type == 7 || (int)val3.Type == 0) { continue; } ItemProto val4 = ((ProtoSet<ItemProto>)(object)LDB.items).Select(val3.Results[0]); if (val4 != null) { Variant variant = Rule(((Proto)val3).ID, ((Proto)val4).ID, val3.Items, val4.CanBuild, val3.Results.Length); if (variant != null && Exists(variant.Extra[0])) { list3.Add(new KeyValuePair<RecipeProto, Variant>(val3, variant)); } } } list3.Sort((KeyValuePair<RecipeProto, Variant> a, KeyValuePair<RecipeProto, Variant> b) => (a.Value.Tech == b.Value.Tech) ? ((a.Key.GridIndex == b.Key.GridIndex) ? ((Proto)a.Key).ID.CompareTo(((Proto)b.Key).ID) : a.Key.GridIndex.CompareTo(b.Key.GridIndex)) : a.Value.Tech.CompareTo(b.Value.Tech)); int next = 0; int num7 = 0; foreach (KeyValuePair<RecipeProto, Variant> item9 in list3) { if (Add(item9.Value, item9.Key, () => (next < cells.Count) ? cells[next++] : 0)) { num7++; } } int[] array2 = new int[4] { Plugin.TechUnlocking(1116), Plugin.TechUnlocking(1303), Plugin.TechUnlocking(1303), Gate(7017, 7014, 7002, 7019) }; List<TechProto> list4 = new List<TechProto>(); for (int num8 = 0; num8 < TechNames.Length; num8++) { if (unlocks[num8].Count != 0) { int after = num8 switch { 3 => afterEnrichment, 0 => afterCrushing, _ => 1980 + num8 - 1, }; TechProto item4 = Plugin.NewTech(1980 + num8, Lang.T(TechNames[num8]), Lang.T(TechDescs[num8]), "BUGOreEnrichment/" + ((num8 == 3) ? "tab" : "tab-precious"), after, array2[num8], num8 + 2, unlocks[num8].ToArray(), new Vector2(x0 + (float)num8 * dx, y)); list4.Add(item4); } } int num9 = Plugin.Append<RecipeProto>((ProtoSet<RecipeProto>)(object)LDB.recipes, (IList<RecipeProto>)made); Plugin.Insert(list4.ToArray()); for (int num10 = 0; num10 < made.Count; num10++) { made[num10].Preload(num9 + num10); } List<string> list5 = new List<string>(); foreach (RecipeProto item10 in made) { if ((Object)(object)item10.iconSprite == (Object)null) { list5.Add(((Proto)item10).ID + " " + ((Proto)item10).Name); } } if (list5.Count > 0) { Plugin.Log.LogWarning((object)("Gold and silver recipes without a picture: " + string.Join(", ", list5.ToArray()))); } Plugin.Log.LogInfo((object)("Gold and silver: " + made.Count + " recipes (" + num7 + " of " + list3.Count + " recipes with electronic parts) and " + list4.Count + " techs; " + missing + " left out (no such item or normal recipe here), " + taken + " ids taken, " + loops + " would close a loop, " + noRoom + " no free cell")); foreach (RecipeProto item11 in made) { hashSet.Add(((Proto)item11).ID); } return hashSet; bool Add(Variant variant2, RecipeProto val5, Func<int> grid) { //IL_00e0: 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_011e: Unknown result type (might be due to invalid IL or missing references) if (val5 == null || !Make(variant2, val5.Items, val5.ItemCounts, val5.Results, val5.ResultCounts, out var items, out var counts, out var results, out var resultCounts)) { missing++; return false; } if (((ProtoSet<RecipeProto>)(object)LDB.recipes).Exist(variant2.Id)) { taken++; return false; } if (Catalysis.Reaches(makes, results, items)) { loops++; return false; } int num11 = grid(); if (num11 == 0) { noRoom++; return false; } string name2 = ((Proto)((ProtoSet<ItemProto>)(object)LDB.items).Select(variant2.Product)).name; RecipeProto val6 = New(variant2.Id, name2 + Lang.T(variant2.Suffix), (variant2.Type != 0) ? variant2.Type : ((int)val5.Type), val5.TimeSpend * variant2.BatchesOut, items, counts, results, resultCounts, num11); val6.NonProductive = val5.NonProductive; val6.Handcraft = val6.Type == val5.Type && val5.Handcraft; int[] extra = variant2.Extra; foreach (int num12 in extra) { val6.Handcraft &= !(((ProtoSet<ItemProto>)(object)LDB.items).Select(num12)?.IsFluid ?? true); } int num13 = 0; List<string> list6 = new List<string>(); for (int l = 0; l < variant2.Extra.Length; l++) { int num14 = Array.IndexOf(items, variant2.Extra[l]); num13 += counts[num14]; list6.Add(counts[num14] + " " + ((Proto)((ProtoSet<ItemProto>)(object)LDB.items).Select(variant2.Extra[l])).name); } val6.Description = Lang.F("{0} {1} from {2} batches of the normal inputs and {3}. The normal recipe makes {4} from the same inputs.", resultCounts[0], name2, variant2.BatchesIn, string.Join(Lang.T(" and "), list6.ToArray()), val5.ResultCounts[0] * variant2.BatchesIn) + "\n" + Lang.F("Each extra unit gives {0} more {1}.", ((double)(resultCounts[0] - val5.ResultCounts[0] * variant2.BatchesIn) / (double)num13).ToString("0.##", CultureInfo.InvariantCulture), name2); Edge(items, results); copied[((Proto)val6).ID] = val5; Mark(val6, variant2.Product, variant2.Badge); made.Add(val6); unlocks[variant2.Tech].Add(((Proto)val6).ID); return true; } int Column(string group, int key) { if (!cols.TryGetValue(group, out var value)) { value = (cols[group] = new Dictionary<int, int>()); } if (!value.TryGetValue(key, out var value2)) { value2 = (value[key] = value.Count + 1); } return value2; } void Edge(int[] from, int[] to) { foreach (int key in from) { if (!makes.TryGetValue(key, out var value)) { value = (makes[key] = new HashSet<int>()); } foreach (int item5 in to) { value.Add(item5); } } } static bool Exists(int num11) { return ((ProtoSet<ItemProto>)(object)LDB.items).Select(num11) != null; } } private static int Gate(params int[] items) { int num = 0; for (int i = 0; i < items.Length; i++) { int num2 = Plugin.TechUnlocking(items[i]); TechProto val = ((num2 > 0) ? ((ProtoSet<TechProto>)(object)LDB.techs).Select(num2) : null); if (val != null && (num == 0 || val.Position.x > ((ProtoSet<TechProto>)(object)LDB.techs).Select(num).Position.x)) { num = num2; } } return num; } private static string Describe(int id) { return id switch { 9601 => "Copper dust refined in sulfuric acid gives as much copper as smelting, and anode slime besides.", 9602 => "Sulfuric acid dissolves the copper left in the slime; gold and silver stay behind as dust.", 9603 => "Gold dust smelted into ingots.", 9604 => "Silver dust smelted into ingots.", 9605 => "Nitric acid parts silver from gold: more of both from the same slime than sulfuric acid gives.", 9606 => "Gold dust refined by electrolysis in hydrochloric acid: three ingots from two dust.", _ => "Washing with seawater gives as much dust as washing with water, and salt besides.", }; } internal static RecipeProto New(int id, string name, int type, int time, int[] items, int[] counts, int[] results, int[] resultCounts, int grid) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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) //IL_004b: 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_005b: 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_006e: 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_0081: Expected O, but got Unknown return new RecipeProto { ID = id, Name = name, Description = "", Type = (ERecipeType)(byte)type, Handcraft = false, Explicit = true, TimeSpend = time, Items = items, ItemCounts = counts, Results = results, ResultCounts = resultCounts, GridIndex = grid, IconPath = "", IconTag = "", NonProductive = false }; } internal static void Mark(RecipeProto r, int item, string badge) { plain[((Proto)r).ID] = item; r.IconPath = "BUGOreEnrichment/pv/" + ((Proto)r).ID; Catalysis.Mark(r, () => IconFor(((Proto)r).ID), badge); } internal static void RefreshItemRecipes() { MethodInfo methodInfo = AccessTools.Method(typeof(ItemProto), "FindRecipes", (Type[])null, (Type[])null); ItemProto[] dataArray = ((ProtoSet<ItemProto>)(object)LDB.items).dataArray; foreach (ItemProto val in dataArray) { if (val != null) { val.recipes = null; methodInfo.Invoke(val, null); } } } } public static class Recycling { public class Ammo { public int Id; public int Grid; public int Key; } public class Group { public string Name; public int Source; public int First = 1; public int Row; public int Slot; public List<int> Main = new List<int>(); public List<int> Bonus = new List<int>(); } public class Level { public Group Group; public int Number; public int InN; public int Hardest; public int Type; public int[] Out; public int[] OutN; public int Shown => Group.First + Number - 1; } public class Recipe { public int[] In; public int[] InN; public int[] Out; public int[] OutN; public int Type; } public const int Base = 9656; public const int Count = 44; public const int TechId = 1984; public const int LevelTechBase = 1850; public const int MaxLevels = 3; public static readonly int[] AmmoSources = new int[6] { 5201, 5202, 5203, 5204, 5206, 5205 }; public static readonly Dictionary<int, double> DropWorth = new Dictionary<int, double> { { 5201, 20.0 }, { 5202, 25.0 }, { 5203, 30.0 }, { 5204, 40.0 }, { 5205, 60.0 }, { 5206, 3.0 } }; public static readonly Dictionary<int, double> FixedCosts = DropWorth.Concat(new KeyValuePair<int, double>[1] { new KeyValuePair<int, double>(1208, 8.0) }).ToDictionary((KeyValuePair<int, double> p) => p.Key, (KeyValuePair<int, double> p) => p.Value); public static readonly int[] Dyson = new int[6] { 1501, 1125, 1502, 1503, 2311, 2312 }; public static readonly int[] Units = new int[5] { 5101, 5102, 5103, 5111, 5112 }; public static readonly int[] Power = new int[7] { 2206, 2213, 2211, 2208, 2210, 6261, 6221 }; public static readonly int[] Buildings = new int[3] { 2318, 2319, 3006 }; private static readonly Dictionary<int, string> AmmoNames = new Dictionary<int, string> { { 1, "Magazines" }, { 3, "Shells" }, { 4, "Plasma Capsules" }, { 5, "Missiles" }, { 6, "Jamming Capsules" }, { 102, "Explosive Units" } }; private static readonly string[] Roman = new string[11] { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X" }; public static int Key(int ammoType, int bombType) { if (ammoType == 0) { if (bombType == 0) { return 0; } return 100 + bombType; } return ammoType; } public static Dictionary<int, double> Costs(IList<Recipe> recipes, IDictionary<int, double> fixedCosts, Dictionary<int, int> types) { Dictionary<int, double> dictionary = new Dictionary<int, double>(fixedCosts); HashSet<int> hashSet = new HashSet<int>(recipes.SelectMany((Recipe r) => r.Out)); foreach (Recipe recipe in recipes) { int[] array = recipe.In; foreach (int num2 in array) { if (!hashSet.Contains(num2) && !dictionary.ContainsKey(num2)) { dictionary[num2] = 1.0; } } } int num3 = 0; int num4 = 1; for (; num3 < 200; num3++) { if (num4 <= 0) { break; } num4 = 0; foreach (Recipe recipe2 in recipes) { double num5 = 0.0; bool flag = recipe2.In.Length != 0; for (int num6 = 0; num6 < recipe2.In.Length && flag; num6++) { if (dictionary.TryGetValue(recipe2.In[num6], out var value)) { num5 += value * (double)recipe2.InN[num6]; } else { flag = false; } } int num7 = recipe2.OutN.Sum(); if (!flag || num7 <= 0)