using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using MoreShipUpgrades.API; using MoreShipUpgrades.Managers; using MoreShipUpgrades.UI.TerminalNodes; using TerminalApi; using TerminalApi.Classes; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("LGUTerminalBridge")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+8c5521e37f37e3d76518a16d04e5d1051842f105")] [assembly: AssemblyProduct("LGUTerminalBridge")] [assembly: AssemblyTitle("LGUTerminalBridge")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 LGUTerminalBridge { internal static class CompatibleNounHelper { internal static CompatibleNoun Create(TerminalKeyword noun, TerminalNode result) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown CompatibleNoun val = (CompatibleNoun)FormatterServices.GetUninitializedObject(typeof(CompatibleNoun)); val.noun = noun; val.result = result; return val; } } [HarmonyPatch(typeof(Terminal))] [HarmonyAfter(new string[] { "mrov.TerminalFormatter", "darmuh.TerminalStuff", "atomic.terminalapi", "com.malco.lethalcompany.moreshipupgrades" })] internal static class TerminalStartPatch { [HarmonyPatch("Start")] [HarmonyPostfix] private static void Postfix(Terminal __instance) { Plugin.CachedTerminal = __instance; Plugin.Log.LogInfo((object)"Terminal reference cached."); try { BuildCustomNodesPatch.RegisterPendingKeywords(); } catch (Exception arg) { Plugin.Log.LogError((object)$"Deferred keyword registration error: {arg}"); } } } [HarmonyPatch(typeof(Terminal))] [HarmonyAfter(new string[] { "mrov.TerminalFormatter", "darmuh.TerminalStuff", "atomic.terminalapi", "com.malco.lethalcompany.moreshipupgrades" })] internal static class LoadNewNodePatch { [HarmonyPatch("LoadNewNode")] [HarmonyPrefix] private static void Prefix(TerminalNode node) { try { foreach (KeyValuePair item in Plugin.NameToConfirmNode) { if (!((Object)(object)item.Value == (Object)(object)node)) { continue; } string upgradeName = item.Key; CustomTerminalNode val = ((IEnumerable)Plugin.SharedUpgradeNodes).FirstOrDefault((Func)((CustomTerminalNode n) => n.OriginalName == upgradeName || n.Name == upgradeName)); if (val != null) { int currentPrice = val.GetCurrentPrice(); string arg = ""; if (val.MaxUpgrade > 0) { arg = $" (Tier {val.GetCurrentLevel()} -> {val.GetCurrentLevel() + 1})"; } node.displayText = $"You are about to purchase: {val.Name}{arg}\nCost: ${currentPrice}\n\nPlease CONFIRM or DENY.\n\n"; } break; } } catch (Exception arg2) { Plugin.Log.LogError((object)$"LoadNewNode prefix error: {arg2}"); } } [HarmonyPatch("LoadNewNode")] [HarmonyPostfix] private static void Postfix(Terminal __instance, TerminalNode node) { try { if (Plugin.PurchaseNodeToName.TryGetValue(node, out var upgradeName)) { CustomTerminalNode val = ((IEnumerable)Plugin.SharedUpgradeNodes).FirstOrDefault((Func)((CustomTerminalNode n) => n.OriginalName == upgradeName || n.Name == upgradeName)); if (val == null) { Plugin.Log.LogWarning((object)("Could not find upgrade node for '" + upgradeName + "'.")); } else { ExecuteLGUPurchase(__instance, val, node); } } } catch (Exception arg) { Plugin.Log.LogError((object)$"LoadNewNode postfix error: {arg}"); } } private static void ExecuteLGUPurchase(Terminal terminal, CustomTerminalNode upgradeNode, TerminalNode displayNode) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected I4, but got Unknown int currentPrice = upgradeNode.GetCurrentPrice(); if (currentPrice == int.MaxValue) { displayNode.displayText = upgradeNode.Name + " is already at maximum level!\n\n"; return; } bool flag = false; PurchaseMode purchaseMode = upgradeNode.PurchaseMode; switch ((int)purchaseMode) { case 1: if (terminal.groupCredits >= currentPrice) { terminal.groupCredits -= currentPrice; terminal.SyncGroupCreditsServerRpc(terminal.groupCredits, terminal.numberOfItemsInDropship); flag = true; } break; case 0: flag = true; break; case 2: if (terminal.groupCredits >= currentPrice) { terminal.groupCredits -= currentPrice; terminal.SyncGroupCreditsServerRpc(terminal.groupCredits, terminal.numberOfItemsInDropship); } flag = true; break; } if (!flag) { displayNode.displayText = $"You cannot afford {upgradeNode.Name}! (${currentPrice})\n\n"; return; } UpgradeApi.TriggerUpgradeRankup(upgradeNode); string text = ((upgradeNode.MaxUpgrade > 0) ? $" to tier {upgradeNode.GetCurrentLevel()}" : ""); displayNode.displayText = "Successfully purchased " + upgradeNode.Name + text + "!\n\n"; Plugin.Log.LogInfo((object)$"Purchased LGU upgrade: {upgradeNode.Name} for ${currentPrice}"); } } [HarmonyPatch(typeof(UpgradeBus), "BuildCustomNodes")] [HarmonyAfter(new string[] { "com.malco.lethalcompany.moreshipupgrades" })] internal static class BuildCustomNodesPatch { private static List<(CustomTerminalNode node, string keyName)> _pending = new List<(CustomTerminalNode, string)>(); [HarmonyPostfix] private static void Postfix() { try { RefreshSharedUpgrades(); } catch (Exception arg) { Plugin.Log.LogError((object)$"BuildCustomNodes postfix error: {arg}"); } } private static void RefreshSharedUpgrades() { List upgradeNodes = UpgradeApi.GetUpgradeNodes(); if (upgradeNodes == null || upgradeNodes.Count == 0) { return; } Plugin.SharedUpgradeNodes.Clear(); _pending.Clear(); foreach (CustomTerminalNode item in upgradeNodes) { if (item.SharedUpgrade && item.Visible && (item.UnlockPrice > 0 || (item.Prices != null && item.Prices.Length != 0))) { Plugin.SharedUpgradeNodes.Add(item); item.Visible = false; string text = item.OriginalName ?? item.Name; if (!Plugin.RegisteredKeywords.Contains(text)) { _pending.Add((item, text)); } } } Plugin.Log.LogInfo((object)$"Refreshed {Plugin.SharedUpgradeNodes.Count} shared upgrades, {_pending.Count} pending."); if ((Object)(object)Plugin.CachedTerminal != (Object)null) { RegisterPendingKeywords(); } else { Plugin.Log.LogInfo((object)"Terminal not ready. Keywords deferred to Terminal.Start."); } if (!Plugin.DarmuhPresent) { return; } try { StorePlusMenuPatch.AddLGUUpgradesToMenu(); } catch (Exception arg) { Plugin.Log.LogError((object)$"StorePlus LGU push error: {arg}"); } } internal static void RegisterPendingKeywords() { Terminal val = Plugin.CachedTerminal; if ((Object)(object)val == (Object)null) { val = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null) { return; } } if (_pending.Count == 0) { return; } TerminalKeyword val2 = null; TerminalKeyword val3 = null; TerminalKeyword buyKw = null; if ((Object)(object)val.terminalNodes != (Object)null && val.terminalNodes.allKeywords != null) { TerminalKeyword[] allKeywords = val.terminalNodes.allKeywords; foreach (TerminalKeyword val4 in allKeywords) { if (val4.word == "confirm") { val2 = val4; } else if (val4.word == "deny") { val3 = val4; } else if (val4.word == "buy") { buyKw = val4; } } } if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null) { Plugin.Log.LogWarning((object)"confirm/deny keywords not found. Skipping."); return; } int num = 0; foreach (var (upgradeNode, text) in _pending) { if (!Plugin.RegisteredKeywords.Contains(text)) { try { RegisterBuyKeyword(val, upgradeNode, text, val2, val3, buyKw); Plugin.RegisteredKeywords.Add(text); num++; } catch (Exception arg) { Plugin.Log.LogError((object)$"Failed to register '{text}': {arg}"); } } } Plugin.Log.LogInfo((object)$"Registered {num} buy keywords."); _pending.Clear(); } private static void RegisterBuyKeyword(Terminal terminal, CustomTerminalNode upgradeNode, string keyName, TerminalKeyword confirmKw, TerminalKeyword denyKw, TerminalKeyword buyKw) { string text = upgradeNode.Name.ToLowerInvariant().Replace(" ", "-"); int currentPrice = upgradeNode.GetCurrentPrice(); TerminalNode val = ScriptableObject.CreateInstance(); val.displayText = "Purchased " + upgradeNode.Name + "!\n\n"; val.clearPreviousText = true; val.maxCharactersToType = 25; Plugin.NameToPurchaseNode[keyName] = val; Plugin.PurchaseNodeToName[val] = keyName; TerminalNode val2 = ScriptableObject.CreateInstance(); val2.displayText = "Cancelled order.\n\n"; val2.clearPreviousText = true; TerminalNode val3 = ScriptableObject.CreateInstance(); val3.displayText = $"You are about to purchase: {upgradeNode.Name}\nCost: ${currentPrice}\n\nPlease CONFIRM or DENY.\n\n"; val3.clearPreviousText = true; val3.overrideOptions = true; val3.maxCharactersToType = 25; val3.itemCost = currentPrice; Plugin.NameToConfirmNode[keyName] = val3; val3.terminalOptions = (CompatibleNoun[])(object)new CompatibleNoun[2] { CompatibleNounHelper.Create(confirmKw, val), CompatibleNounHelper.Create(denyKw, val2) }; TerminalKeyword val4 = TerminalApi.CreateTerminalKeyword(text, false, val3); if (!((Object)(object)val4 == (Object)null) && (Object)(object)buyKw != (Object)null) { CompatibleNoun[] compatibleNouns = buyKw.compatibleNouns; int num = ((compatibleNouns != null) ? compatibleNouns.Length : 0); CompatibleNoun[] array = (CompatibleNoun[])(object)new CompatibleNoun[num + 1]; if (num > 0) { Array.Copy(compatibleNouns, array, num); } array[num] = CompatibleNounHelper.Create(val4, val3); buyKw.compatibleNouns = array; TerminalApi.AddTerminalKeyword(val4); Plugin.Log.LogInfo((object)("Registered buy keyword '" + text + "' for: " + upgradeNode.Name)); } } } [HarmonyPatch] [HarmonyAfter(new string[] { "com.malco.lethalcompany.moreshipupgrades" })] internal static class ContractsPatch { private static bool Prepare() { return Chainloader.PluginInfos.ContainsKey("com.malco.lethalcompany.moreshipupgrades"); } [HarmonyPatch(typeof(Terminal), "Start")] [HarmonyPostfix] [HarmonyPriority(200)] private static void TerminalStart_Postfix(Terminal __instance) { try { CleanContractsFromLGUHelp(__instance); } catch (Exception arg) { Plugin.Log.LogError((object)$"Contracts cleanup error: {arg}"); } } private static void CleanContractsFromLGUHelp(Terminal terminal) { if ((Object)(object)terminal.terminalNodes == (Object)null || terminal.terminalNodes.allKeywords == null) { return; } TerminalKeyword[] allKeywords = terminal.terminalNodes.allKeywords; foreach (TerminalKeyword val in allKeywords) { if (!(val.word == "lgu") || !((Object)(object)val.specialKeywordResult != (Object)null)) { continue; } TerminalNode specialKeywordResult = val.specialKeywordResult; if (specialKeywordResult.displayText != null && specialKeywordResult.displayText.Contains("contract")) { string[] value = (from l in specialKeywordResult.displayText.Split('\n') where !l.ToLowerInvariant().Contains("contract") select l).ToArray(); specialKeywordResult.displayText = string.Join("\n", value); Plugin.Log.LogInfo((object)"Removed contracts references from LGU help text."); } break; } Plugin.Log.LogInfo((object)"Contracts command verified as standalone."); } } [HarmonyPatch] [HarmonyAfter(new string[] { "darmuh.TerminalStuff", "com.malco.lethalcompany.moreshipupgrades", "atomic.terminalapi" })] internal static class StorePlusMenuPatch { private static Type t_StorePlus; private static Type t_StoreMenuItem; private static Type t_MenuItem; private static ConstructorInfo ctor_Name; private static ConstructorInfo ctor_Keyword; private static PropertyInfo p_Name; private static PropertyInfo p_NestedMenus; private static MethodInfo m_SetParentMenu; private static FieldInfo f_keyword; private static FieldInfo f_StoreItem; internal static object FurnitureMenu; internal static object ContractsMenu; private static object _theMainMenu; private static object _upgrades; private static object _buyables; private static object _vehicles; private static object _suits; private static bool _menusCreated; private static HashSet _addedLGUKeywords = new HashSet(); private static bool Prepare() { if (!Chainloader.PluginInfos.ContainsKey("darmuh.TerminalStuff")) { return false; } t_StorePlus = AccessTools.TypeByName("TerminalStuff.StoreTweaks.StorePlus"); t_StoreMenuItem = AccessTools.TypeByName("TerminalStuff.StoreTweaks.StoreMenuItem"); if (t_StorePlus == null || t_StoreMenuItem == null) { Plugin.Log.LogWarning((object)"StorePlus types not found."); return false; } t_MenuItem = t_StoreMenuItem.BaseType; ctor_Name = t_StoreMenuItem.GetConstructor(new Type[1] { typeof(string) }); ctor_Keyword = t_StoreMenuItem.GetConstructor(new Type[3] { typeof(string), typeof(string), t_MenuItem }); p_Name = t_StoreMenuItem.GetProperty("Name") ?? t_MenuItem?.GetProperty("Name"); p_NestedMenus = t_StoreMenuItem.GetProperty("NestedMenus") ?? t_MenuItem?.GetProperty("NestedMenus"); m_SetParentMenu = t_MenuItem?.GetMethod("SetParentMenu", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { t_MenuItem }, null); f_keyword = AccessTools.Field(t_StoreMenuItem, "keyword"); f_StoreItem = AccessTools.Field(t_StoreMenuItem, "StoreItem"); if (ctor_Name == null || p_NestedMenus == null || m_SetParentMenu == null) { Plugin.Log.LogWarning((object)"Reflection incomplete. StorePlus patches disabled."); return false; } Plugin.Log.LogInfo((object)"StorePlus reflection targets resolved."); return true; } private static MethodBase TargetMethod() { return AccessTools.Method(t_StorePlus, "GetStoreItems", (Type[])null, (Type[])null); } [HarmonyPostfix] private static void Postfix() { try { CacheStaticFields(); if (!_menusCreated) { CreateMenuStructure(); _menusCreated = true; } MoveFurnitureItems(); RemoveLGUFromExternalMods(); AddLGUUpgradesToMenu(); ReorderMainMenu(); } catch (Exception arg) { Plugin.Log.LogError((object)$"StorePlus restructure error: {arg}"); } } private static void CacheStaticFields() { _theMainMenu = AccessTools.Field(t_StorePlus, "TheMainMenu")?.GetValue(null); _upgrades = AccessTools.Field(t_StorePlus, "Upgrades")?.GetValue(null); _buyables = AccessTools.Field(t_StorePlus, "Buyables")?.GetValue(null); _vehicles = AccessTools.Field(t_StorePlus, "Vehicles")?.GetValue(null); _suits = AccessTools.Field(t_StorePlus, "Suits")?.GetValue(null); } private static void CreateMenuStructure() { if (_theMainMenu != null && _upgrades != null) { p_Name?.SetValue(_upgrades, "Upgrades"); FurnitureMenu = ctor_Name.Invoke(new object[1] { "Furniture" }); m_SetParentMenu.Invoke(FurnitureMenu, new object[1] { _theMainMenu }); if (ctor_Keyword != null) { ContractsMenu = ctor_Keyword.Invoke(new object[3] { "Contracts", "contracts", _theMainMenu }); } else { ContractsMenu = ctor_Name.Invoke(new object[1] { "Contracts" }); m_SetParentMenu.Invoke(ContractsMenu, new object[1] { _theMainMenu }); } Plugin.Log.LogInfo((object)"Created Furniture and Contracts StorePlus submenus."); } } private static void MoveFurnitureItems() { if (_upgrades == null || FurnitureMenu == null || !(p_NestedMenus.GetValue(_upgrades) is IList list) || list.Count == 0) { return; } List list2 = new List(); foreach (object item in list) { if (IsItemFurniture(item)) { list2.Add(item); } } foreach (object item2 in list2) { m_SetParentMenu.Invoke(item2, new object[1] { FurnitureMenu }); } if (list2.Count > 0) { Plugin.Log.LogDebug((object)$"Moved {list2.Count} furniture items to Furniture menu."); } } private static bool IsItemFurniture(object menuItem) { if (f_StoreItem == null) { return false; } object value = f_StoreItem.GetValue(menuItem); if (value == null) { return false; } FieldInfo fieldInfo = AccessTools.Field(value.GetType(), "Unlockable"); if (fieldInfo == null) { return false; } object value2 = fieldInfo.GetValue(value); if (value2 == null) { return false; } FieldInfo fieldInfo2 = AccessTools.Field(value2.GetType(), "alwaysInStock"); if (fieldInfo2 == null) { return false; } return !(bool)fieldInfo2.GetValue(value2); } private static void RemoveLGUFromExternalMods() { object obj = AccessTools.Field(t_StorePlus, "ExternalMods")?.GetValue(null); if (obj == null || !(p_NestedMenus.GetValue(obj) is IList list)) { return; } List list2 = new List(); foreach (object item in list) { if (!(f_keyword == null)) { string text = f_keyword.GetValue(item) as string; if (text == "lgu" || text == "contracts") { list2.Add(item); } } } foreach (object item2 in list2) { list.Remove(item2); } } internal static void AddLGUUpgradesToMenu() { if (_upgrades == null || (ctor_Keyword == null && ctor_Name == null)) { return; } if (_addedLGUKeywords.Count > 0) { if (p_NestedMenus.GetValue(_upgrades) is IList list) { List list2 = new List(); foreach (object item2 in list) { if (!(f_keyword == null) && f_keyword.GetValue(item2) is string item && _addedLGUKeywords.Contains(item)) { list2.Add(item2); } } foreach (object item3 in list2) { list.Remove(item3); } } _addedLGUKeywords.Clear(); } foreach (CustomTerminalNode sharedUpgradeNode in Plugin.SharedUpgradeNodes) { string text = sharedUpgradeNode.Name.ToLowerInvariant().Replace(" ", "-"); if (_addedLGUKeywords.Contains(text)) { continue; } try { int currentPrice = sharedUpgradeNode.GetCurrentPrice(); string text2; if (currentPrice == int.MaxValue || (sharedUpgradeNode.Unlocked && sharedUpgradeNode.CurrentUpgrade >= sharedUpgradeNode.MaxUpgrade)) { text2 = sharedUpgradeNode.Name + " [MAXED]"; } else { string arg = ((sharedUpgradeNode.MaxUpgrade > 0) ? $" [T{sharedUpgradeNode.GetCurrentLevel()}/{sharedUpgradeNode.MaxUpgrade + 1}]" : ""); text2 = $"${currentPrice} {sharedUpgradeNode.Name}{arg}"; } if (ctor_Keyword != null) { ctor_Keyword.Invoke(new object[3] { text2, text, _upgrades }); } else { object obj = ctor_Name.Invoke(new object[1] { text2 }); m_SetParentMenu.Invoke(obj, new object[1] { _upgrades }); } _addedLGUKeywords.Add(text); Plugin.Log.LogDebug((object)("Added LGU upgrade: " + text2)); } catch (Exception arg2) { Plugin.Log.LogError((object)$"Failed to add '{sharedUpgradeNode.Name}' to StorePlus: {arg2}"); } } } private static void ReorderMainMenu() { if (_theMainMenu == null || !(p_NestedMenus.GetValue(_theMainMenu) is IList list) || list.Count == 0) { return; } Type type = list.GetType(); MethodInfo method = type.GetMethod("RemoveAt", new Type[1] { typeof(int) }); MethodInfo method2 = type.GetMethod("Insert"); object[] array = new object[6] { _buyables, _upgrades, _vehicles, FurnitureMenu, ContractsMenu, _suits }; List list2 = new List(); for (int i = 0; i < list.Count; i++) { list2.Add(list[i]); } List list3 = new List(); object[] array2 = array; foreach (object obj in array2) { if (obj == null) { continue; } for (int k = 0; k < list2.Count; k++) { if (list2[k] == obj) { list3.Add(obj); list2.RemoveAt(k); break; } } } list3.AddRange(list2); for (int num = list.Count - 1; num >= 0; num--) { method.Invoke(list, new object[1] { num }); } for (int l = 0; l < list3.Count; l++) { method2.Invoke(list, new object[2] { l, list3[l] }); } IEnumerable values = list3.Select((object o) => p_Name?.GetValue(o)?.ToString() ?? "?"); Plugin.Log.LogInfo((object)("Menu reordered: " + string.Join(", ", values))); } } [HarmonyPatch] internal static class TerminalPCsRenamePatch { private static readonly Regex RxPCs = new Regex("\\bPCs\\b", RegexOptions.Compiled); private static readonly Regex RxPC = new Regex("\\bPC\\b", RegexOptions.Compiled); internal static string Rename(string s) { if (string.IsNullOrEmpty(s)) { return s; } s = s.Replace("Player Credits", "Player BXP"); s = s.Replace("player credits", "player BXP"); s = s.Replace("PLAYER CREDITS", "PLAYER BXP"); s = RxPCs.Replace(s, "BXPs"); s = RxPC.Replace(s, "BXP"); return s; } [HarmonyPatch(typeof(Terminal), "TextPostProcess")] [HarmonyPostfix] private static void TextPostProcess_Postfix(ref string __result) { __result = Rename(__result); } [HarmonyPatch(typeof(Terminal), "LoadNewNode")] [HarmonyPostfix] private static void LoadNewNode_Postfix(TerminalNode node) { if ((Object)(object)node != (Object)null && !string.IsNullOrEmpty(node.displayText)) { node.displayText = Rename(node.displayText); } } } [HarmonyPatch(typeof(HUDManager), "DisplayTip")] internal static class DisplayTipBxpRenamePatch { [HarmonyPrefix] private static void Prefix(ref string headerText, ref string bodyText) { try { headerText = TerminalPCsRenamePatch.Rename(headerText); bodyText = TerminalPCsRenamePatch.Rename(bodyText); } catch (Exception arg) { Plugin.Log.LogError((object)$"DisplayTip rename prefix error: {arg}"); } } } [HarmonyPatch] internal static class CurrencyManagerNotificationPatch { [CompilerGenerated] private sealed class d__3 : IEnumerable, IEnumerable, IEnumerator, IEnumerator, IDisposable { private int <>1__state; private MethodBase <>2__current; private int <>l__initialThreadId; MethodBase IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__3(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (_addCurrencyAmountFromQuota != null) { <>2__current = _addCurrencyAmountFromQuota; <>1__state = 1; return true; } goto IL_004a; case 1: <>1__state = -1; goto IL_004a; case 2: { <>1__state = -1; break; } IL_004a: if (_tradePlayerCreditsClientRpc != null) { <>2__current = _tradePlayerCreditsClientRpc; <>1__state = 2; return true; } break; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__3(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private static MethodInfo _addCurrencyAmountFromQuota; private static MethodInfo _tradePlayerCreditsClientRpc; private static bool Prepare() { if (!Chainloader.PluginInfos.ContainsKey("com.malco.lethalcompany.moreshipupgrades")) { return false; } Type type = AccessTools.TypeByName("MoreShipUpgrades.Managers.CurrencyManager"); if (type == null) { return false; } _addCurrencyAmountFromQuota = AccessTools.Method(type, "AddCurrencyAmountFromQuota", (Type[])null, (Type[])null); _tradePlayerCreditsClientRpc = AccessTools.Method(type, "TradePlayerCreditsClientRpc", (Type[])null, (Type[])null); if (!(_addCurrencyAmountFromQuota != null)) { return _tradePlayerCreditsClientRpc != null; } return true; } [IteratorStateMachine(typeof(d__3))] private static IEnumerable TargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__3(-2); } [HarmonyPostfix] private static void Postfix(MethodBase __originalMethod) { Plugin.Log.LogDebug((object)("[BXP] LGU notification fired: " + __originalMethod?.Name + " (rewritten via DisplayTip prefix).")); } } [HarmonyPatch(typeof(Debug))] internal static class FontWarningSuppressionPatch { [HarmonyPatch("LogWarning", new Type[] { typeof(object) })] [HarmonyPrefix] private static bool Prefix(object message) { if (message is string text && text.Contains("3270-Regular SDF")) { return false; } return true; } } [BepInPlugin("com.lguterminalbridge", "LGUTerminalBridge", "1.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string GUID = "com.lguterminalbridge"; public const string NAME = "LGUTerminalBridge"; public const string VERSION = "1.2.0"; internal const string DARMUH_GUID = "darmuh.TerminalStuff"; internal static ManualLogSource Log; internal static Terminal CachedTerminal; internal static List SharedUpgradeNodes = new List(); internal static Dictionary NameToPurchaseNode = new Dictionary(); internal static Dictionary NameToConfirmNode = new Dictionary(); internal static Dictionary PurchaseNodeToName = new Dictionary(); internal static HashSet RegisteredKeywords = new HashSet(); internal static bool DarmuhPresent => Chainloader.PluginInfos.ContainsKey("darmuh.TerminalStuff"); private void Awake() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; new Harmony("com.lguterminalbridge").PatchAll(); RegisterStoreCommands(); if (DarmuhPresent) { Log.LogInfo((object)"darmuh's TerminalStuff detected. StorePlus patches will activate."); } else { Log.LogInfo((object)"darmuh's TerminalStuff not detected. TerminalApi fallback active."); } Log.LogInfo((object)"LGUTerminalBridge v1.2.0 loaded!"); } private void RegisterStoreCommands() { //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_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_0048: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown CommandInfo val = new CommandInfo { Title = "Furniture", Category = "Store", Description = "Browse available furniture and decorations.", DisplayTextSupplier = BuildFurnitureDisplay }; TerminalApi.AddCommand("furniture", val, (string)null, true); CommandInfo val2 = new CommandInfo { Title = "Upgrades", Category = "Store", Description = "Browse available ship upgrades.", DisplayTextSupplier = BuildUpgradesDisplay }; TerminalApi.AddCommand("upgrades", val2, (string)null, true); Log.LogInfo((object)"Registered 'furniture' and 'upgrades' terminal commands."); } internal static string BuildFurnitureDisplay() { Terminal val = CachedTerminal; if ((Object)(object)val == (Object)null) { val = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null) { return "Terminal not available.\n\n"; } } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("FURNITURE STORE"); stringBuilder.AppendLine("==============================\n"); stringBuilder.AppendLine("Decorations rotate each quota. Type BUY [item] to purchase.\n"); if (val.ShipDecorSelection == null || val.ShipDecorSelection.Count == 0) { stringBuilder.AppendLine("[No furniture available]\n"); } else { foreach (TerminalNode item in val.ShipDecorSelection) { stringBuilder.AppendLine($"* {item.creatureName} // Price: ${item.itemCost}"); } stringBuilder.AppendLine(); } stringBuilder.AppendLine($"Your balance is ${val.groupCredits}.\n"); return stringBuilder.ToString(); } internal static string BuildUpgradesDisplay() { Terminal val = CachedTerminal; if ((Object)(object)val == (Object)null) { val = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null) { return "Terminal not available.\n\n"; } } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("UPGRADES STORE"); stringBuilder.AppendLine("==============================\n"); stringBuilder.AppendLine("Type BUY [item] to purchase.\n"); StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null) { for (int i = 0; i < instance.unlockablesList.unlockables.Count; i++) { UnlockableItem val2 = instance.unlockablesList.unlockables[i]; if ((Object)(object)val2.shopSelectionNode != (Object)null && val2.alwaysInStock) { string arg = ((val2.hasBeenUnlockedByPlayer || val2.alreadyUnlocked) ? " [OWNED]" : ""); stringBuilder.AppendLine($"* {val2.shopSelectionNode.creatureName} // Price: ${val2.shopSelectionNode.itemCost}{arg}"); } } } if (SharedUpgradeNodes.Count > 0) { stringBuilder.AppendLine("\n-- Shared Upgrades (LGU) --\n"); foreach (CustomTerminalNode sharedUpgradeNode in SharedUpgradeNodes) { int currentPrice = sharedUpgradeNode.GetCurrentPrice(); string text = sharedUpgradeNode.Name.ToLowerInvariant().Replace(" ", "-"); string text2 = ""; if (sharedUpgradeNode.MaxUpgrade > 0) { text2 = $" [Tier {sharedUpgradeNode.GetCurrentLevel()}/{sharedUpgradeNode.MaxUpgrade + 1}]"; } if (currentPrice == int.MaxValue || (sharedUpgradeNode.Unlocked && sharedUpgradeNode.CurrentUpgrade >= sharedUpgradeNode.MaxUpgrade)) { stringBuilder.AppendLine("* " + sharedUpgradeNode.Name + text2 + " [MAXED]"); continue; } string text3 = (sharedUpgradeNode.Unlocked ? " [OWNED]" : ""); stringBuilder.AppendLine($"* {sharedUpgradeNode.Name} ({text}) // ${currentPrice}{text2}{text3}"); } } stringBuilder.AppendLine($"\nYour balance is ${val.groupCredits}.\n"); return stringBuilder.ToString(); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "LGUTerminalBridge"; public const string PLUGIN_NAME = "LGUTerminalBridge"; public const string PLUGIN_VERSION = "1.0.0"; } }