Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Interactive Store v1.0.2
BepInEx/plugins/InteractiveStore/InteractiveStore.dll
Decompiled 4 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using InteractiveStore.Configuration; using InteractiveStore.NetcodePatcher; using InteractiveStore.UI.Application; using InteractiveStore.UI.Cursor; using InteractiveTerminalAPI.Compat; using InteractiveTerminalAPI.UI; using InteractiveTerminalAPI.UI.Application; using InteractiveTerminalAPI.UI.Cursor; using InteractiveTerminalAPI.UI.Page; using InteractiveTerminalAPI.UI.Screen; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] internal class <Module> { static <Module>() { } } 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 WeatherProbe.Misc { internal static class Metadata { public const string GUID = "com.github.WhiteSpike.InteractiveStore"; public const string NAME = "Interactive Store"; public const string VERSION = "1.0.0"; } } namespace InteractiveStore { [BepInPlugin("com.github.WhiteSpike.InteractiveStore", "Interactive Store", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { internal static readonly Harmony harmony = new Harmony("com.github.WhiteSpike.InteractiveStore"); internal static ManualLogSource mls; internal static ModConfiguration config; private void Awake() { config = new ModConfiguration(((BaseUnityPlugin)this).Config); InteractiveTerminalManager.RegisterApplication<StoreApplication>(config.ItemStoreCommandList.Value, config.ItemStoreCommandCaseSensitive.Value); InteractiveTerminalManager.RegisterApplication<UnlockableStoreApplication>(config.DecorationStoreCommandList.Value, config.DecorationStoreCommandCaseSensitive.Value); InteractiveTerminalManager.RegisterApplication<VehicleApplication>(config.VehicleStoreCommandList.Value, config.VehicleStoreCommandCaseSensitive.Value); mls = ((BaseUnityPlugin)this).Logger; mls.LogInfo((object)"Interactive Store 1.0.0 has been loaded successfully."); } } public static class PluginInfo { public const string PLUGIN_GUID = "InteractiveStore"; public const string PLUGIN_NAME = "ExtendDeadline"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace InteractiveStore.UI.Cursor { public class ItemCursorElement : CursorOutputElement<int> { private const int NAME_LENGTH = 30; private const char WHITE_SPACE = ' '; public Item item; private float salePercentage; private Terminal terminal; public ItemCursorElement(Item item, float salePercentage, Action pressAction, Terminal terminal) { this.item = item; this.salePercentage = salePercentage; ((CursorElement)this).Action = pressAction; this.terminal = terminal; ((CursorCounterElement)this).Counter = 0; base.Func = (int x) => x * Mathf.CeilToInt((float)item.creditsWorth * salePercentage); this.terminal = terminal; } public override string GetText(int availableLength) { StringBuilder stringBuilder = new StringBuilder(); int groupCredits = terminal.groupCredits; if (!((CursorElement)this).Active((CursorElement)(object)this)) { stringBuilder.Append("<color=#66666666>"); } string value = ((item.itemName.Length > 30) ? item.itemName.Substring(0, 30) : (item.itemName + new string(' ', Mathf.Max(0, 30 - item.itemName.Length)))); stringBuilder.Append(value); int num = Mathf.CeilToInt((float)item.creditsWorth * salePercentage); if (num > groupCredits) { stringBuilder.Append(string.Format("<color={0}>", "#8B0000")); stringBuilder.Append($"{num}$"); stringBuilder.Append("</color>"); } else { stringBuilder.Append($"{num}$"); } if (salePercentage < 1f) { stringBuilder.Append(' '); stringBuilder.Append($"({(1f - salePercentage) * 100f:F0}% OFF)"); } stringBuilder.Append(' '); stringBuilder.Append($"⇐{((CursorCounterElement)this).Counter}⇒"); if (!((CursorElement)this).Active((CursorElement)(object)this)) { stringBuilder.Append("</color>"); } return stringBuilder.ToString(); } } public class UnlockableCursorElement : CursorElement { private const int NAME_LENGTH = 30; private const char WHITE_SPACE = ' '; public TerminalNode node; public UnlockableItem unlockable; private Terminal terminal; public UnlockableCursorElement(TerminalNode node, Terminal terminal) { this.node = node; this.terminal = terminal; unlockable = StartOfRound.Instance.unlockablesList.unlockables[node.shipUnlockableID]; ((CursorElement)this).Active = (CursorElement x) => IsAvailableForPurchase(x); } private bool IsAvailableForPurchase(CursorElement x) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) int itemCost = node.itemCost; int result; if (terminal.groupCredits >= itemCost && (StartOfRound.Instance.inShipPhase || StartOfRound.Instance.shipHasLanded)) { AnimatorStateInfo currentAnimatorStateInfo = StartOfRound.Instance.shipAnimator.GetCurrentAnimatorStateInfo(0); if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).tagHash == Animator.StringToHash("ShipIdle") && (terminal.ShipDecorSelection.Contains(node) || unlockable.alwaysInStock || (node.buyUnlockable && !((Object)(object)unlockable.shopSelectionNode == (Object)null)))) { result = ((!unlockable.hasBeenUnlockedByPlayer && !unlockable.alreadyUnlocked) ? 1 : 0); goto IL_00c3; } } result = 0; goto IL_00c3; IL_00c3: return (byte)result != 0; } public override string GetText(int availableLength) { StringBuilder stringBuilder = new StringBuilder(); int groupCredits = terminal.groupCredits; if (!((CursorElement)this).Active((CursorElement)(object)this)) { if (unlockable.hasBeenUnlockedByPlayer || unlockable.alreadyUnlocked) { stringBuilder.Append("<color=#026440>"); } else { stringBuilder.Append("<color=#66666666>"); } } string value = ((node.creatureName.Length > 30) ? node.creatureName.Substring(0, 30) : (node.creatureName + new string(' ', Mathf.Max(0, 30 - node.creatureName.Length)))); stringBuilder.Append(value); int num = Mathf.CeilToInt((float)node.itemCost); if (num > groupCredits) { stringBuilder.Append(string.Format("<color={0}>", "#8B0000")); stringBuilder.Append($"{num}$"); stringBuilder.Append("</color>"); } else { stringBuilder.Append($"{num}$"); } if (!((CursorElement)this).Active((CursorElement)(object)this)) { stringBuilder.Append("</color>"); } return stringBuilder.ToString(); } } public class VehicleCursorElement : CursorElement { private const int NAME_LENGTH = 20; private const char WHITE_SPACE = ' '; public BuyableVehicle vehicle; public float salePercentage; public int vehicleIndex = -1; private Terminal terminal; internal VehicleController controller; public VehicleCursorElement(BuyableVehicle vehicle, float salePercentage, int vehicleIndex, Terminal terminal) { this.vehicle = vehicle; this.terminal = terminal; this.vehicleIndex = vehicleIndex; this.salePercentage = salePercentage; ((CursorElement)this).Active = (CursorElement x) => IsAvailableForPurchase(x); controller = Object.FindObjectOfType<VehicleController>(); } private bool IsAvailableForPurchase(CursorElement x) { int creditsWorth = vehicle.creditsWorth; return (terminal.groupCredits >= creditsWorth || terminal.hasWarrantyTicket) && terminal.numberOfItemsInDropship <= 0 && (Object)(object)controller == (Object)null && !terminal.vehicleInDropship; } public override string GetText(int availableLength) { StringBuilder stringBuilder = new StringBuilder(); int groupCredits = terminal.groupCredits; if (!((CursorElement)this).Active((CursorElement)(object)this)) { stringBuilder.Append("<color=#66666666>"); } string text = vehicle.vehicleDisplayName + " " + (terminal.hasWarrantyTicket ? "(WARRANTY)" : ""); string value = ((text.Length > 20) ? text.Substring(0, 20) : (text + new string(' ', Mathf.Max(0, 20 - text.Length)))); stringBuilder.Append(value); int num = Mathf.CeilToInt((float)vehicle.creditsWorth); if (terminal.hasWarrantyTicket) { stringBuilder.Append("<s>"); } if (num > groupCredits) { stringBuilder.Append(string.Format("<color={0}>", "#8B0000")); stringBuilder.Append($"{num}$"); stringBuilder.Append("</color>"); } else { stringBuilder.Append($"{num}$"); } if (terminal.hasWarrantyTicket) { stringBuilder.Append("</s>"); } if (salePercentage < 1f) { stringBuilder.Append(' '); stringBuilder.Append($"({(1f - salePercentage) * 100f:F0}% OFF)"); } if (!((CursorElement)this).Active((CursorElement)(object)this)) { stringBuilder.Append("</color>"); } return stringBuilder.ToString(); } } } namespace InteractiveStore.UI.Application { internal class StoreApplication : CounterPageApplication<CursorOutputElement<int>> { private const string SCREEN_TITLE = "The Company Store"; private const string INITIAL_SCREEN_DESCRIPTION = "Select the amount of items you wish to purchase from each entry."; private const string COLORED_OUTPUT_ITEM_SCREEN_FORMAT = "<color={0}>{1}/{2}</color>"; private const string OUTPUT_SCREEN_ITEM_FORMAT = "{0}/{1}"; private const string OUTPUT_SCREEN_CREDIT_FORMAT = "{0}$"; private const string COLORED_OUTPUT_SCREEN_CREDIT_FORMAT = "<color={0}>{1}$</color>"; private const string CONFIRM_PURCHASE_FORMAT = "Do you wish to purchase the selected {0} items for {1}$ ? \n {2}"; private const string PURCHASE_LISTING_FORMAT = "{0}x {1} ({2}$)\n"; private const string NO_ITEMS_SELECTED_ERROR = "No items were selected for purchasing..."; private const string NOT_ENOUGH_CREDITS_ERROR = "You do not have enough Company Credits to purchase the selected items..."; private const string MAXIMUM_CAPACITY_ERROR = "The amount of items selected and already purchased surpasses the maximum capacity of the item dropship..."; private const string VEHICLE_IN_POD_ERROR = "You are unable to purchase items when a vehicle is loaded into the drop pod..."; private Item[] buyableItems = null; private int[] salePercentages = null; private CursorOutputElement<int>[] itemCursorElements = null; private const int PURCHASE_AUDIO_SYNCED_INDEX = 0; protected override int GetEntriesPerPage<K>(K[] entries) { return 10; } public override void Initialization() { buyableItems = ((TerminalApplication)this).terminal.buyableItemsList; salePercentages = ((TerminalApplication)this).terminal.itemSalesPercentages; itemCursorElements = new CursorOutputElement<int>[buyableItems.Length]; int num = 0; (Item[][], BaseCursorMenu<CursorOutputElement<int>>[], IScreen[]) pageEntries = ((PageApplication<CursorOutputElement<int>>)(object)this).GetPageEntries<Item>(buyableItems); Item[][] item = pageEntries.Item1; BaseCursorMenu<CursorOutputElement<int>>[] cursorMenus = pageEntries.Item2; IScreen[] screens = pageEntries.Item3; for (int i = 0; i < item.Length; i++) { Item[] array = item[i]; CursorOutputElement<int>[] array2 = new CursorOutputElement<int>[array.Length]; cursorMenus[i] = (BaseCursorMenu<CursorOutputElement<int>>)(object)CursorMenu<CursorOutputElement<int>>.Create(0, '>', array2, new Func<CursorOutputElement<int>, CursorOutputElement<int>, int>[3] { CompareName, CompareDescendingPrice, CompareAscendingPrice }); cursorMenus[i].sortingIndex = -1; BaseCursorMenu<CursorOutputElement<int>> val = cursorMenus[i]; ITextElement[] elements = (ITextElement[])(object)new ITextElement[3] { (ITextElement)TextElement.Create("Select the amount of items you wish to purchase from each entry."), (ITextElement)TextElement.Create(" "), (ITextElement)val }; screens[i] = (IScreen)(object)new BoxedOutputScreen<int, string> { Title = "The Company Store", elements = elements, Input = () => ApplyInputFunction(), Output = (int x) => ApplyOutputFunction(x) }; for (int j = 0; j < array.Length; j++) { Item val2 = array[j]; if ((Object)(object)val2 == (Object)null) { continue; } int num2 = j + i * array.Length; int pageIndex = i; array2[j] = new ItemCursorElement(buyableItems[num2], (float)salePercentages[num2] / 100f, delegate { TryBuySelectedItems(delegate { ((BaseInteractiveApplication<CursorOutputElement<int>>)(object)this).SwitchScreen(screens[pageIndex], cursorMenus[pageIndex], true); }); }, ((TerminalApplication)this).terminal); itemCursorElements[num++] = array2[j]; } } ((PageApplication<CursorOutputElement<int>>)(object)this).currentPage = ((PageApplication<CursorOutputElement<int>>)(object)this).initialPage; ((BaseInteractiveApplication<CursorOutputElement<int>>)(object)this).currentCursorMenu = ((PageApplication<CursorOutputElement<int>>)(object)this).initialPage.GetCurrentCursorMenu(); ((TerminalApplication)this).currentScreen = ((PageElement)((PageApplication<CursorOutputElement<int>>)(object)this).initialPage).GetCurrentScreen(); } private int CompareName(CursorElement cursor1, CursorElement cursor2) { if (cursor1 == null) { return 1; } if (cursor2 == null) { return -1; } ItemCursorElement itemCursorElement = cursor1 as ItemCursorElement; ItemCursorElement itemCursorElement2 = cursor2 as ItemCursorElement; string itemName = itemCursorElement.item.itemName; string itemName2 = itemCursorElement2.item.itemName; return itemName.CompareTo(itemName2); } private int CompareDescendingPrice(CursorElement cursor1, CursorElement cursor2) { if (cursor1 == null) { return 1; } if (cursor2 == null) { return -1; } ItemCursorElement itemCursorElement = cursor1 as ItemCursorElement; ItemCursorElement itemCursorElement2 = cursor2 as ItemCursorElement; int creditsWorth = itemCursorElement.item.creditsWorth; int creditsWorth2 = itemCursorElement2.item.creditsWorth; return creditsWorth.CompareTo(creditsWorth2); } private int CompareAscendingPrice(CursorElement cursor1, CursorElement cursor2) { if (cursor1 == null) { return 1; } if (cursor2 == null) { return -1; } ItemCursorElement itemCursorElement = cursor1 as ItemCursorElement; ItemCursorElement itemCursorElement2 = cursor2 as ItemCursorElement; int creditsWorth = itemCursorElement.item.creditsWorth; int creditsWorth2 = itemCursorElement2.item.creditsWorth; return creditsWorth2.CompareTo(creditsWorth); } private string ApplyOutputFunction(int x) { StringBuilder stringBuilder = new StringBuilder(); int num = 0; for (int i = 0; i < itemCursorElements.Length; i++) { ItemCursorElement itemCursorElement = itemCursorElements[i] as ItemCursorElement; int counter = ((CursorCounterElement)itemCursorElement).Counter; if (counter != 0) { num += counter; } } if (num + ((TerminalApplication)this).terminal.numberOfItemsInDropship == 12) { stringBuilder.Append(string.Format("<color={0}>{1}/{2}</color>", "#FFFF00", num + ((TerminalApplication)this).terminal.numberOfItemsInDropship, 12)); } else if (num + ((TerminalApplication)this).terminal.numberOfItemsInDropship > 12) { stringBuilder.Append(string.Format("<color={0}>{1}/{2}</color>", "#8B0000", num + ((TerminalApplication)this).terminal.numberOfItemsInDropship, 12)); } else { stringBuilder.Append($"{num + ((TerminalApplication)this).terminal.numberOfItemsInDropship}/{12}"); } stringBuilder.Append(' '); if (((TerminalApplication)this).terminal.groupCredits < x) { stringBuilder.Append(string.Format("<color={0}>{1}$</color>", "#8B0000", x)); } else { stringBuilder.Append($"{x}$"); } int sortingIndex = ((BaseInteractiveApplication<CursorOutputElement<int>>)(object)this).currentCursorMenu.sortingIndex; if (1 == 0) { } string text = sortingIndex switch { 0 => "Sort: Alphabetical [" + InputActionRebindingExtensions.GetBindingDisplayString(InputUtils_Compat.ChangeApplicationSortingKey, (DisplayStringOptions)0, (string)null) + "]", 1 => "Sort: Price (Des.) [" + InputActionRebindingExtensions.GetBindingDisplayString(InputUtils_Compat.ChangeApplicationSortingKey, (DisplayStringOptions)0, (string)null) + "]", 2 => "Sort: Price (Asc.) [" + InputActionRebindingExtensions.GetBindingDisplayString(InputUtils_Compat.ChangeApplicationSortingKey, (DisplayStringOptions)0, (string)null) + "]", _ => "Sort: None [" + InputActionRebindingExtensions.GetBindingDisplayString(InputUtils_Compat.ChangeApplicationSortingKey, (DisplayStringOptions)0, (string)null) + "]", }; if (1 == 0) { } string text2 = text; return text2 + "|" + stringBuilder.ToString(); } private void TryBuySelectedItems(Action backAction) { if (((TerminalApplication)this).terminal.vehicleInDropship) { ErrorMessage("The Company Store", "You are unable to purchase items when a vehicle is loaded into the drop pod...", backAction, ""); return; } int totalItems = 0; int totalCost = 0; StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < itemCursorElements.Length; i++) { ItemCursorElement itemCursorElement = itemCursorElements[i] as ItemCursorElement; int counter = ((CursorCounterElement)itemCursorElement).Counter; if (counter != 0) { totalItems += counter; totalCost += ((CursorOutputElement<int>)itemCursorElement).ApplyFunction(); stringBuilder.Append($"{((CursorCounterElement)itemCursorElement).Counter}x {itemCursorElement.item.itemName} ({((CursorOutputElement<int>)itemCursorElement).ApplyFunction()}$)\n"); } } if (totalItems <= 0) { ErrorMessage("The Company Store", "No items were selected for purchasing...", backAction, ""); return; } if (((TerminalApplication)this).terminal.groupCredits < totalCost) { ErrorMessage("The Company Store", "You do not have enough Company Credits to purchase the selected items...", backAction, ""); return; } if (((TerminalApplication)this).terminal.numberOfItemsInDropship + totalItems > 12) { ErrorMessage("The Company Store", "The amount of items selected and already purchased surpasses the maximum capacity of the item dropship...", backAction, ""); return; } Confirm("The Company Store", $"Do you wish to purchase the selected {totalItems} items for {totalCost}$ ? \n {stringBuilder.ToString()}", delegate { PurchaseSelectedItems(totalItems, totalCost, backAction); }, backAction); } private void PurchaseSelectedItems(int totalItems, int totalCost, Action backAction) { ((TerminalApplication)this).terminal.groupCredits = Mathf.Clamp(((TerminalApplication)this).terminal.groupCredits - totalCost, 0, 10000000); while (totalItems > 0) { for (int i = 0; i < itemCursorElements.Length; i++) { if (totalItems <= 0) { break; } if (!(itemCursorElements[i] is ItemCursorElement itemCursorElement)) { continue; } int num = ((CursorCounterElement)itemCursorElement).Counter; if (num != 0) { while (num > 0) { ((TerminalApplication)this).terminal.orderedItemsFromTerminal.Add(i); Terminal terminal = ((TerminalApplication)this).terminal; terminal.numberOfItemsInDropship++; num--; totalItems--; } ((CursorCounterElement)itemCursorElement).Counter = 0; } } } ((TerminalApplication)this).terminal.PlayTerminalAudioServerRpc(0); if (!((NetworkBehaviour)((TerminalApplication)this).terminal).IsServer) { ((TerminalApplication)this).terminal.SyncBoughtItemsWithServer(((TerminalApplication)this).terminal.orderedItemsFromTerminal.ToArray(), ((TerminalApplication)this).terminal.numberOfItemsInDropship); } else { ((TerminalApplication)this).terminal.SyncGroupCreditsClientRpc(((TerminalApplication)this).terminal.groupCredits, ((TerminalApplication)this).terminal.numberOfItemsInDropship); } backAction(); } private int ApplyInputFunction() { int num = 0; for (int i = 0; i < itemCursorElements.Length; i++) { num += itemCursorElements[i].ApplyFunction(); } return num; } protected void Confirm(string title, string description, Action confirmAction, Action declineAction, string additionalMessage = "") { CursorOutputElement<int>[] array = new CursorOutputElement<int>[2] { CursorOutputElement<int>.Create("Confirm", "", confirmAction, 0, (Func<int, int>)null, (Func<CursorElement, bool>)null, true, false), CursorOutputElement<int>.Create("Cancel", "", declineAction, 0, (Func<int, int>)null, (Func<CursorElement, bool>)null, true, false) }; CursorMenu<CursorOutputElement<int>> val = CursorMenu<CursorOutputElement<int>>.Create(0, '>', array, (Func<CursorOutputElement<int>, CursorOutputElement<int>, int>[])null); ITextElement[] array2 = (ITextElement[])(object)new ITextElement[4] { (ITextElement)TextElement.Create(description), (ITextElement)TextElement.Create(" "), (ITextElement)TextElement.Create(additionalMessage), (ITextElement)val }; IScreen val2 = (IScreen)(object)BoxedScreen.Create(title, array2); ((BaseInteractiveApplication<CursorOutputElement<int>>)(object)this).SwitchScreen(val2, (BaseCursorMenu<CursorOutputElement<int>>)(object)val, false); } protected void ErrorMessage(string title, string description, Action backAction, string error) { CursorOutputElement<int>[] array = new CursorOutputElement<int>[1] { CursorOutputElement<int>.Create("Back", "", backAction, 0, (Func<int, int>)null, (Func<CursorElement, bool>)null, true, false) }; CursorMenu<CursorOutputElement<int>> val = CursorMenu<CursorOutputElement<int>>.Create(0, '>', array, (Func<CursorOutputElement<int>, CursorOutputElement<int>, int>[])null); ITextElement[] array2 = (ITextElement[])(object)new ITextElement[5] { (ITextElement)TextElement.Create(description), (ITextElement)TextElement.Create(" "), (ITextElement)TextElement.Create(error), (ITextElement)TextElement.Create(" "), (ITextElement)val }; IScreen val2 = (IScreen)(object)BoxedScreen.Create(title, array2); ((BaseInteractiveApplication<CursorOutputElement<int>>)(object)this).SwitchScreen(val2, (BaseCursorMenu<CursorOutputElement<int>>)(object)val, false); } } internal class UnlockableStoreApplication : PageApplication<CursorElement> { private const string SCREEN_TITLE = "The Company Store"; private const string INITIAL_SCREEN_DESCRIPTION = "Select the items you wish to purchase."; private const string CONFIRM_PURCHASE_FORMAT = "Do you wish to purchase the selected item for {0}$ ? \n{1}"; private const string NOT_ENOUGH_CREDITS_ERROR = "You do not have enough Company Credits to purchase the selected items..."; private const string NO_PURCHASE_DURING_FLIGHT = "You cannot purchase furniture items while landing/departing..."; private const string UNLOCKABLE_NOT_AVAILABLE = "This item is currently not available for purchase..."; private const string UNLOCKABLE_ALREADY_PURCHASED = "This item was already purchased for your assigned ship..."; private const int PURCHASE_AUDIO_SYNCED_INDEX = 0; protected override int GetEntriesPerPage<K>(K[] entries) { return 10; } public override void Initialization() { List<TerminalNode> list = new List<TerminalNode>(((TerminalApplication)this).terminal.ShipDecorSelection); UnlockableItem val = null; TerminalKeyword[] allKeywords = ((TerminalApplication)this).terminal.terminalNodes.allKeywords; foreach (TerminalKeyword val2 in allKeywords) { if (val2.compatibleNouns != null) { CompatibleNoun[] compatibleNouns = val2.compatibleNouns; foreach (CompatibleNoun val3 in compatibleNouns) { TerminalNode result = val3.result; if (!((Object)(object)result == (Object)null) && result.shipUnlockableID >= 0) { val = StartOfRound.Instance.unlockablesList.unlockables[result.shipUnlockableID]; if (val.alwaysInStock && !list.Contains(result)) { list.Add(result); } } } } TerminalNode specialKeywordResult = val2.specialKeywordResult; if (!((Object)(object)specialKeywordResult == (Object)null) && specialKeywordResult.shipUnlockableID >= 0) { val = StartOfRound.Instance.unlockablesList.unlockables[specialKeywordResult.shipUnlockableID]; if (val.alwaysInStock && !list.Contains(specialKeywordResult)) { list.Add(specialKeywordResult); } } } TerminalNode[] array = list.ToArray(); (TerminalNode[][], BaseCursorMenu<CursorElement>[], IScreen[]) pageEntries = base.GetPageEntries<TerminalNode>(array); TerminalNode[][] item = pageEntries.Item1; BaseCursorMenu<CursorElement>[] cursorMenus = pageEntries.Item2; IScreen[] screens = pageEntries.Item3; for (int k = 0; k < item.Length; k++) { TerminalNode[] array2 = item[k]; CursorElement[] array3 = (CursorElement[])(object)new CursorElement[array2.Length]; cursorMenus[k] = (BaseCursorMenu<CursorElement>)(object)CursorMenu<CursorElement>.Create(0, '>', array3, new Func<CursorElement, CursorElement, int>[3] { CompareName, CompareDescendingPrice, CompareAscendingPrice }); cursorMenus[k].sortingIndex = -1; BaseCursorMenu<CursorElement> val4 = cursorMenus[k]; ITextElement[] elements = (ITextElement[])(object)new ITextElement[3] { (ITextElement)TextElement.Create("Select the items you wish to purchase."), (ITextElement)TextElement.Create(" "), (ITextElement)val4 }; screens[k] = (IScreen)(object)new BoxedOutputScreen<int, string> { Title = "The Company Store", elements = elements, Input = () => ApplyInputFunction(), Output = (int x) => ApplyOutputFunction(x) }; for (int l = 0; l < array2.Length; l++) { TerminalNode val5 = array2[l]; if ((Object)(object)val5 == (Object)null) { continue; } int num = l + k * array2.Length; int pageIndex = k; int num2 = l; UnlockableCursorElement cursor = new UnlockableCursorElement(array[num], ((TerminalApplication)this).terminal); ((CursorElement)cursor).Action = delegate { TryBuySelectedItem((CursorElement)(object)cursor, delegate { ((BaseInteractiveApplication<CursorElement>)(object)this).SwitchScreen(screens[pageIndex], cursorMenus[pageIndex], true); }); }; array3[l] = (CursorElement)(object)cursor; } } base.currentPage = base.initialPage; ((BaseInteractiveApplication<CursorElement>)(object)this).currentCursorMenu = base.initialPage.GetCurrentCursorMenu(); ((TerminalApplication)this).currentScreen = ((PageElement)base.initialPage).GetCurrentScreen(); } private int CompareName(CursorElement cursor1, CursorElement cursor2) { if (cursor1 == null) { return 1; } if (cursor2 == null) { return -1; } UnlockableCursorElement unlockableCursorElement = cursor1 as UnlockableCursorElement; UnlockableCursorElement unlockableCursorElement2 = cursor2 as UnlockableCursorElement; string creatureName = unlockableCursorElement.node.creatureName; string creatureName2 = unlockableCursorElement2.node.creatureName; return creatureName.CompareTo(creatureName2); } private int CompareDescendingPrice(CursorElement cursor1, CursorElement cursor2) { if (cursor1 == null) { return 1; } if (cursor2 == null) { return -1; } UnlockableCursorElement unlockableCursorElement = cursor1 as UnlockableCursorElement; UnlockableCursorElement unlockableCursorElement2 = cursor2 as UnlockableCursorElement; int itemCost = unlockableCursorElement.node.itemCost; int itemCost2 = unlockableCursorElement2.node.itemCost; return itemCost.CompareTo(itemCost2); } private int CompareAscendingPrice(CursorElement cursor1, CursorElement cursor2) { if (cursor1 == null) { return 1; } if (cursor2 == null) { return -1; } UnlockableCursorElement unlockableCursorElement = cursor1 as UnlockableCursorElement; UnlockableCursorElement unlockableCursorElement2 = cursor2 as UnlockableCursorElement; int itemCost = unlockableCursorElement.node.itemCost; int itemCost2 = unlockableCursorElement2.node.itemCost; return itemCost2.CompareTo(itemCost); } private string ApplyOutputFunction(int x) { StringBuilder stringBuilder = new StringBuilder(); int sortingIndex = ((BaseInteractiveApplication<CursorElement>)(object)this).currentCursorMenu.sortingIndex; if (1 == 0) { } string text = sortingIndex switch { 0 => "Sort: Alphabetical [" + InputActionRebindingExtensions.GetBindingDisplayString(InputUtils_Compat.ChangeApplicationSortingKey, (DisplayStringOptions)0, (string)null) + "]", 1 => "Sort: Price (Des.) [" + InputActionRebindingExtensions.GetBindingDisplayString(InputUtils_Compat.ChangeApplicationSortingKey, (DisplayStringOptions)0, (string)null) + "]", 2 => "Sort: Price (Asc.) [" + InputActionRebindingExtensions.GetBindingDisplayString(InputUtils_Compat.ChangeApplicationSortingKey, (DisplayStringOptions)0, (string)null) + "]", _ => "Sort: None [" + InputActionRebindingExtensions.GetBindingDisplayString(InputUtils_Compat.ChangeApplicationSortingKey, (DisplayStringOptions)0, (string)null) + "]", }; if (1 == 0) { } string text2 = text; return text2 ?? ""; } private void TryBuySelectedItem(CursorElement node, Action backAction) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); UnlockableCursorElement cursor = node as UnlockableCursorElement; int totalCost = cursor.node.itemCost; if (((TerminalApplication)this).terminal.groupCredits < totalCost) { ((InteractiveTerminalApplication<CursorElement>)(object)this).ErrorMessage("The Company Store", "You do not have enough Company Credits to purchase the selected items...", backAction, ""); return; } if (StartOfRound.Instance.inShipPhase || StartOfRound.Instance.shipHasLanded) { AnimatorStateInfo currentAnimatorStateInfo = StartOfRound.Instance.shipAnimator.GetCurrentAnimatorStateInfo(0); if (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).tagHash == Animator.StringToHash("ShipIdle")) { UnlockableItem unlockable = cursor.unlockable; if (!((TerminalApplication)this).terminal.ShipDecorSelection.Contains(cursor.node) && !unlockable.alwaysInStock && (!cursor.node.buyUnlockable || (Object)(object)unlockable.shopSelectionNode == (Object)null)) { ((InteractiveTerminalApplication<CursorElement>)(object)this).ErrorMessage("The Company Store", "This item is currently not available for purchase...", backAction, ""); return; } if (unlockable.hasBeenUnlockedByPlayer || unlockable.alreadyUnlocked) { ((InteractiveTerminalApplication<CursorElement>)(object)this).ErrorMessage("The Company Store", "This item was already purchased for your assigned ship...", backAction, ""); return; } ((InteractiveTerminalApplication<CursorElement>)(object)this).Confirm("The Company Store", $"Do you wish to purchase the selected item for {totalCost}$ ? \n{stringBuilder.ToString()}", (Action)delegate { PurchaseSelectedItems(cursor.node, totalCost, backAction); }, backAction, ""); return; } } ((InteractiveTerminalApplication<CursorElement>)(object)this).ErrorMessage("The Company Store", "You cannot purchase furniture items while landing/departing...", backAction, ""); } private void PurchaseSelectedItems(TerminalNode node, int totalCost, Action backAction) { ((TerminalApplication)this).terminal.groupCredits = Mathf.Clamp(((TerminalApplication)this).terminal.groupCredits - totalCost, 0, 10000000); ((TerminalApplication)this).terminal.PlayTerminalAudioServerRpc(0); StartOfRound.Instance.BuyShipUnlockableServerRpc(node.shipUnlockableID, ((TerminalApplication)this).terminal.groupCredits); backAction(); } private int ApplyInputFunction() { return 0; } } internal class VehicleApplication : PageApplication<CursorElement> { private const string SCREEN_TITLE = "The Company Store"; private const string INITIAL_SCREEN_DESCRIPTION = "Select the items you wish to purchase."; private const string CONFIRM_PURCHASE_FORMAT = "Do you wish to purchase the selected item for {0}$ ? \n{1}"; private const string NOT_ENOUGH_CREDITS_ERROR = "You do not have enough Company Credits to purchase the selected item..."; private const string ITEMS_IN_POD_ERROR = "You are unable to purchase vehicles when there are items loaded in the pod..."; private const string VEHICLE_ALREADY_PURCHASED_ERROR = "You already have a vehicle in your possession..."; private const string VEHICLE_IN_DELIVERY_ERROR = "A vehicle is already being delivered to you..."; private BuyableVehicle[] buyableVehicles = null; private int[] salePercentages = null; private const int PURCHASE_AUDIO_SYNCED_INDEX = 0; protected override int GetEntriesPerPage<K>(K[] entries) { return 10; } public override void Initialization() { buyableVehicles = ((TerminalApplication)this).terminal.buyableVehicles; salePercentages = ((TerminalApplication)this).terminal.itemSalesPercentages; (BuyableVehicle[][], BaseCursorMenu<CursorElement>[], IScreen[]) pageEntries = base.GetPageEntries<BuyableVehicle>(buyableVehicles); BuyableVehicle[][] item = pageEntries.Item1; BaseCursorMenu<CursorElement>[] cursorMenus = pageEntries.Item2; IScreen[] screens = pageEntries.Item3; for (int i = 0; i < item.Length; i++) { BuyableVehicle[] array = item[i]; CursorElement[] array2 = (CursorElement[])(object)new CursorElement[array.Length]; cursorMenus[i] = (BaseCursorMenu<CursorElement>)(object)CursorMenu<CursorElement>.Create(0, '>', array2, new Func<CursorElement, CursorElement, int>[3] { CompareName, CompareDescendingPrice, CompareAscendingPrice }); cursorMenus[i].sortingIndex = -1; BaseCursorMenu<CursorElement> val = cursorMenus[i]; ITextElement[] elements = (ITextElement[])(object)new ITextElement[3] { (ITextElement)TextElement.Create("Select the items you wish to purchase."), (ITextElement)TextElement.Create(" "), (ITextElement)val }; screens[i] = (IScreen)(object)new BoxedOutputScreen<int, string> { Title = "The Company Store", elements = elements, Input = () => ApplyInputFunction(), Output = (int x) => ApplyOutputFunction(x) }; for (int j = 0; j < array.Length; j++) { BuyableVehicle val2 = array[j]; if (val2 == null) { continue; } int num = j + i * array.Length; int pageIndex = i; int num2 = j; VehicleCursorElement cursor = new VehicleCursorElement(buyableVehicles[num], (float)salePercentages[((TerminalApplication)this).terminal.buyableItemsList.Length + num] / 100f, num, ((TerminalApplication)this).terminal); ((CursorElement)cursor).Action = delegate { TryBuySelectedItem((CursorElement)(object)cursor, delegate { ((BaseInteractiveApplication<CursorElement>)(object)this).SwitchScreen(screens[pageIndex], cursorMenus[pageIndex], true); }); }; array2[j] = (CursorElement)(object)cursor; } } base.currentPage = base.initialPage; ((BaseInteractiveApplication<CursorElement>)(object)this).currentCursorMenu = base.initialPage.GetCurrentCursorMenu(); ((TerminalApplication)this).currentScreen = ((PageElement)base.initialPage).GetCurrentScreen(); } private int CompareName(CursorElement cursor1, CursorElement cursor2) { if (cursor1 == null) { return 1; } if (cursor2 == null) { return -1; } UnlockableCursorElement unlockableCursorElement = cursor1 as UnlockableCursorElement; UnlockableCursorElement unlockableCursorElement2 = cursor2 as UnlockableCursorElement; string creatureName = unlockableCursorElement.node.creatureName; string creatureName2 = unlockableCursorElement2.node.creatureName; return creatureName.CompareTo(creatureName2); } private int CompareDescendingPrice(CursorElement cursor1, CursorElement cursor2) { if (cursor1 == null) { return 1; } if (cursor2 == null) { return -1; } UnlockableCursorElement unlockableCursorElement = cursor1 as UnlockableCursorElement; UnlockableCursorElement unlockableCursorElement2 = cursor2 as UnlockableCursorElement; int itemCost = unlockableCursorElement.node.itemCost; int itemCost2 = unlockableCursorElement2.node.itemCost; return itemCost.CompareTo(itemCost2); } private int CompareAscendingPrice(CursorElement cursor1, CursorElement cursor2) { if (cursor1 == null) { return 1; } if (cursor2 == null) { return -1; } UnlockableCursorElement unlockableCursorElement = cursor1 as UnlockableCursorElement; UnlockableCursorElement unlockableCursorElement2 = cursor2 as UnlockableCursorElement; int itemCost = unlockableCursorElement.node.itemCost; int itemCost2 = unlockableCursorElement2.node.itemCost; return itemCost2.CompareTo(itemCost); } private string ApplyOutputFunction(int x) { StringBuilder stringBuilder = new StringBuilder(); int sortingIndex = ((BaseInteractiveApplication<CursorElement>)(object)this).currentCursorMenu.sortingIndex; if (1 == 0) { } string text = sortingIndex switch { 0 => "Sort: Alphabetical [" + InputActionRebindingExtensions.GetBindingDisplayString(InputUtils_Compat.ChangeApplicationSortingKey, (DisplayStringOptions)0, (string)null) + "]", 1 => "Sort: Price (Des.) [" + InputActionRebindingExtensions.GetBindingDisplayString(InputUtils_Compat.ChangeApplicationSortingKey, (DisplayStringOptions)0, (string)null) + "]", 2 => "Sort: Price (Asc.) [" + InputActionRebindingExtensions.GetBindingDisplayString(InputUtils_Compat.ChangeApplicationSortingKey, (DisplayStringOptions)0, (string)null) + "]", _ => "Sort: None [" + InputActionRebindingExtensions.GetBindingDisplayString(InputUtils_Compat.ChangeApplicationSortingKey, (DisplayStringOptions)0, (string)null) + "]", }; if (1 == 0) { } string text2 = text; return text2 ?? ""; } private void TryBuySelectedItem(CursorElement node, Action backAction) { if (((TerminalApplication)this).terminal.numberOfItemsInDropship > 0) { ((InteractiveTerminalApplication<CursorElement>)(object)this).ErrorMessage("The Company Store", "You are unable to purchase vehicles when there are items loaded in the pod...", backAction, ""); return; } StringBuilder stringBuilder = new StringBuilder(); VehicleCursorElement cursor = node as VehicleCursorElement; int totalCost = cursor.vehicle.creditsWorth; if ((Object)(object)cursor.controller != (Object)null) { ((InteractiveTerminalApplication<CursorElement>)(object)this).ErrorMessage("The Company Store", "You already have a vehicle in your possession...", backAction, ""); return; } if (((TerminalApplication)this).terminal.groupCredits < totalCost && !((TerminalApplication)this).terminal.hasWarrantyTicket) { ((InteractiveTerminalApplication<CursorElement>)(object)this).ErrorMessage("The Company Store", "You do not have enough Company Credits to purchase the selected item...", backAction, ""); return; } if (((TerminalApplication)this).terminal.vehicleInDropship) { ((InteractiveTerminalApplication<CursorElement>)(object)this).ErrorMessage("The Company Store", "A vehicle is already being delivered to you...", backAction, ""); return; } BuyableVehicle item = cursor.vehicle; ((InteractiveTerminalApplication<CursorElement>)(object)this).Confirm("The Company Store", $"Do you wish to purchase the selected item for {((!((TerminalApplication)this).terminal.hasWarrantyTicket) ? totalCost : 0)}$ ? \n{stringBuilder.ToString()}", (Action)delegate { PurchaseSelectedItems(item, cursor.vehicleIndex, (!((TerminalApplication)this).terminal.hasWarrantyTicket) ? totalCost : 0, backAction); }, backAction, ""); } private void PurchaseSelectedItems(BuyableVehicle vehicle, int vehicleIndex, int totalCost, Action backAction) { ((TerminalApplication)this).terminal.groupCredits = Mathf.Clamp(((TerminalApplication)this).terminal.groupCredits - totalCost, 0, 10000000); ((TerminalApplication)this).terminal.PlayTerminalAudioServerRpc(0); ((TerminalApplication)this).terminal.orderedVehicleFromTerminal = vehicleIndex; ((TerminalApplication)this).terminal.vehicleInDropship = true; if (!((NetworkBehaviour)((TerminalApplication)this).terminal).IsServer) { ((TerminalApplication)this).terminal.SyncBoughtVehicleWithServer(((TerminalApplication)this).terminal.orderedVehicleFromTerminal); } else { ((TerminalApplication)this).terminal.hasWarrantyTicket = !((TerminalApplication)this).terminal.hasWarrantyTicket; ((TerminalApplication)this).terminal.BuyVehicleClientRpc(((TerminalApplication)this).terminal.groupCredits, ((TerminalApplication)this).terminal.hasWarrantyTicket); } backAction(); } private int ApplyInputFunction() { return 0; } } } namespace InteractiveStore.Configuration { public class ModConfiguration { public ConfigEntry<string> ItemStoreCommandList { get; set; } public ConfigEntry<bool> ItemStoreCommandCaseSensitive { get; set; } public ConfigEntry<string> DecorationStoreCommandList { get; set; } public ConfigEntry<bool> DecorationStoreCommandCaseSensitive { get; set; } public ConfigEntry<string> VehicleStoreCommandList { get; set; } public ConfigEntry<bool> VehicleStoreCommandCaseSensitive { get; set; } public ModConfiguration(ConfigFile config) { string text = "Initialization"; ItemStoreCommandList = config.Bind<string>(text, "Command Prompts for Item Store", "istore", "List of commands separated by a comma (') to access the interactive item store"); ItemStoreCommandCaseSensitive = config.Bind<bool>(text, "Item Store Prompt Case Sensitivity", false, "Wether the letter case of the command prompts should be relevant or not to bring up the application"); DecorationStoreCommandList = config.Bind<string>(text, "Command Prompts for Decoration/Ship Upgrade Store", "idecor", "List of commands separated by a comma (') to access the interactive decoration/upgrade store"); DecorationStoreCommandCaseSensitive = config.Bind<bool>(text, "Decoration Store Prompt Case Sensitivity", false, "Wether the letter case of the command prompts should be relevant or not to bring up the application"); VehicleStoreCommandList = config.Bind<string>(text, "Command Prompts for Vehicle Store", "icar", "List of commands separated by a comma (') to access the interactive vehicle store"); VehicleStoreCommandCaseSensitive = config.Bind<bool>(text, "Decoration Store Prompt Case Sensitivity", false, "Wether the letter case of the command prompts should be relevant or not to bring up the application"); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } } namespace InteractiveStore.NetcodePatcher { [AttributeUsage(AttributeTargets.Module)] internal class NetcodePatchedAssemblyAttribute : Attribute { } }