using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Overworked.Core; using Overworked.Core.AlwaysGrab; using Overworked.Core.CustomTerminal; using Overworked.Core.Levels; using Overworked.Core.Placement; using Overworked.Core.Scanner; using Overworked.Core.Selling; using Unity.Netcode; using UnityEngine; [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: AssemblyCompany("Overworked")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Overworked")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0+ab047318a31c4cc88a99e75a832c7cc07bffdeaf")] [assembly: AssemblyProduct("Overworked")] [assembly: AssemblyTitle("Overworked")] [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 Overworked { [BepInPlugin("dev.timmywastor.overworked", "Overworked", "1.1.0")] public class Plugin : BaseUnityPlugin { public const string ModGUID = "dev.timmywastor.overworked"; public const string ModName = "Overworked"; public const string ModVersion = "1.1.0"; public static Harmony Harmony = new Harmony("dev.timmywastor.overworked"); public static ManualLogSource OverworkedLogger; public static string PluginFolder; private void Awake() { string location = ((BaseUnityPlugin)this).Info.Location; PluginFolder = Path.GetDirectoryName(location); OverworkedLogger = ((BaseUnityPlugin)this).Logger; OverworkedCore.Initialize(); } } public static class PluginInfo { public const string PLUGIN_GUID = "Overworked"; public const string PLUGIN_NAME = "Overworked"; public const string PLUGIN_VERSION = "1.1.0"; } } namespace Overworked.Core { internal class OverworkedCore { public static void Initialize() { Patch(); } private static void Patch() { Plugin.Harmony.PatchAll(typeof(SellingModule)); Plugin.Harmony.PatchAll(typeof(ItemPlacement)); Plugin.Harmony.PatchAll(typeof(ObjectGrab)); Plugin.Harmony.PatchAll(typeof(LevelLoading)); Plugin.Harmony.PatchAll(typeof(OverworkedTerminal)); } } } namespace Overworked.Core.Selling { internal class SellingModule { private const string _moneyFieldName = "Ow_money"; private static Terminal _currentTerminal; private static int _money = 0; private static readonly string helpHost = ">MOONS\r\nTo see the list of moons the autopilot can route to.\r\n\r\n>STORE\r\nTo see the company store's selection of useful items.\r\n\r\n>BESTIARY\r\nTo see the list of wildlife on record.\r\n\r\n>STORAGE\r\nTo access objects placed into storage.\r\n\r\n>STOCK\r\nStore and manipulate your scrap.\r\n\r\n>OTHER\r\nTo see the list of other commands\r\n\r\n[numberOfItemsOnRoute]\r\n"; private static readonly string helpClient = ">MOONS\r\nTo see the list of moons the autopilot can route to.\r\n\r\n>STORE\r\nTo see the company store's selection of useful items.\r\n\r\n>BESTIARY\r\nTo see the list of wildlife on record.\r\n\r\n>STORAGE\r\nTo access objects placed into storage.\r\n\r\n>OTHER\r\nTo see the list of other commands\r\n\r\n[numberOfItemsOnRoute]\r\n"; private static readonly string commands = ">STOCK [scrap]\nStocks all the available ship scrap.\n\n>STOCK [view] [-S](OPTIONAL,shares it to the chat)\nCheck how much scrap value is stored.\n\n>STOCK SELL [amount]\nAllows you to sell your stored scrap value at the company building.\n\n"; private static readonly string stockMessage = "Welcome to STOCK™.\nuse the following commands to manipulate your stock.\n----------------------------\n\n" + commands; private static readonly string stockScrapMessage = "You have requested to stock all the available ship scrap.\n\nPlease CONFIRM or DENY"; private static readonly string[] _blacklistedItems = new string[3] { "Shotgun", "Ammo", "Kitchen knife" }; private static MethodInfo AddTextMessageServerRpc = AccessTools.Method(typeof(HUDManager), "AddTextMessageServerRpc", (Type[])null, (Type[])null); private static MethodInfo SellAndDisplayItemProfits = AccessTools.Method(typeof(DepositItemsDesk), "SellAndDisplayItemProfits", (Type[])null, (Type[])null); private static IEnumerator ShowTipDelayed() { yield return (object)new WaitForSeconds(2f); HUDManager.Instance.DisplayTip("Overworked", "Scrap stocking module initialized, type 'stock' on the terminal for the list of commands.", false, false, ""); } public static void Initialize(Terminal t) { if (((NetworkBehaviour)StartOfRound.Instance).IsHost) { ((MonoBehaviour)t).StartCoroutine(ShowTipDelayed()); t.terminalNodes.allKeywords[5].specialKeywordResult.displayText = helpHost; _currentTerminal = t; _money = 0; InjectCommands(); Load(); } else { t.terminalNodes.allKeywords[5].specialKeywordResult.displayText = helpClient; } } public static void ResetMoney() { _money = 0; } private static void Load() { string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName; if (ES3.KeyExists("Ow_money", currentSaveFileName)) { _money = ES3.Load("Ow_money", currentSaveFileName); } } public static void Save() { string currentSaveFileName = GameNetworkManager.Instance.currentSaveFileName; ES3.Save("Ow_money", _money, currentSaveFileName); } private static void GetMoneyAndUpdate() { int num = _money; GrabbableObject[] array = Object.FindObjectsOfType(); GrabbableObject[] array2 = array; foreach (GrabbableObject val in array2) { if (val.itemProperties.isScrap && !_blacklistedItems.Contains(val.itemProperties.itemName) && ((NetworkBehaviour)val).IsSpawned && val.isInShipRoom && !val.isHeld) { num += val.scrapValue; ((NetworkBehaviour)val).NetworkObject.Despawn(true); } } _money = num; } public static void SendMessage(string text) { AddTextMessageServerRpc.Invoke(HUDManager.Instance, new object[1] { text }); } private static bool StockSell(int sellAmountParsed) { DepositItemsDesk val = Object.FindObjectOfType(); int num = (int)((float)sellAmountParsed * StartOfRound.Instance.companyBuyingRate); if (sellAmountParsed <= 0 || sellAmountParsed > _money) { return false; } Terminal currentTerminal = _currentTerminal; currentTerminal.groupCredits += num; val.SellItemsClientRpc(num, _currentTerminal.groupCredits, 0, StartOfRound.Instance.companyBuyingRate); SellAndDisplayItemProfits.Invoke(val, new object[2] { num, _currentTerminal.groupCredits }); _money -= sellAmountParsed; return true; } private static void InjectCommands() { TerminalCommand stockCommand = new TerminalCommand("stock"); int currentSellAmount = 0; string currentSellMessage = ""; stockCommand.AddState("default", delegate(string[] args) { if (args.Length > 1) { switch (args[1]) { case "scrap": stockCommand.MoveTo("scrap"); return stockScrapMessage; case "view": if (args.Length > 2 && OverworkedTerminal.Match(args[2], "-share")) { SendMessage($"Terminal/Stock™: ${_money}"); } stockCommand.Finish(); return $"You have obtained ${_money} worth of scrap."; case "sell": { if (args.Length > 2 && int.TryParse(args[2], out var result) && result > 0) { DepositItemsDesk val = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null) { stockCommand.Finish(); return "You must route and land to the company building to sell your stocked scrap."; } currentSellAmount = result; currentSellMessage = $"You have requested to sell ${currentSellAmount} of stocked scrap value.\n\nPlease CONFIRM or DENY"; stockCommand.MoveTo("sell"); return currentSellMessage; } stockCommand.Finish(); return "Invalid amount of scrap value to sell detected, protocol aborted."; } } } stockCommand.Finish(); return stockMessage; }); stockCommand.AddState("sell", delegate(string[] args) { DepositItemsDesk val = Object.FindObjectOfType(); if ((Object)(object)val != (Object)null) { if (OverworkedTerminal.Match(args[0], "confirm")) { stockCommand.Finish(); if (StockSell(currentSellAmount)) { _currentTerminal.PlayTerminalAudioServerRpc(0); SendMessage($"{GameNetworkManager.Instance.localPlayerController.playerUsername} sold ${currentSellAmount}."); return $"Successfully sold ${currentSellAmount}! Your work keeps the company happy."; } return $"You do not have enough stock value to sell ${currentSellAmount}"; } if (OverworkedTerminal.Match(args[0], "deny")) { stockCommand.Finish(); return "You have cancelled the selling protocol."; } return currentSellMessage; } stockCommand.Finish(); return "You must route and land to the company building to sell your stocked scrap."; }); stockCommand.AddState("scrap", delegate(string[] args) { if (StartOfRound.Instance.inShipPhase) { if (OverworkedTerminal.Match(args[0], "confirm")) { stockCommand.Finish(); GetMoneyAndUpdate(); _currentTerminal.PlayTerminalAudioServerRpc(2); SendMessage(GameNetworkManager.Instance.localPlayerController.playerUsername + " stocked the ship scrap."); return $"Successfully stocked the ship scrap, your new balance is ${_money}."; } if (OverworkedTerminal.Match(args[0], "deny")) { stockCommand.Finish(); return "You have cancelled the ship stocking protocol."; } return stockScrapMessage; } stockCommand.Finish(); return "Cannot stock scrap while the ship isn't in orbit."; }); OverworkedTerminal.AddCommand(stockCommand); } [HarmonyPatch(typeof(StartOfRound), "EndOfGame")] [HarmonyPrefix] private static void EndOfGame_Prefix(StartOfRound __instance) { if (((NetworkBehaviour)StartOfRound.Instance).IsHost && __instance.allPlayersDead) { ResetMoney(); } } [HarmonyPatch(typeof(GameNetworkManager), "SaveGameValues")] [HarmonyPrefix] private static void SaveGame_Prefix(GameNetworkManager __instance) { if (((NetworkBehaviour)StartOfRound.Instance).IsHost && StartOfRound.Instance.inShipPhase) { Save(); } } } } namespace Overworked.Core.Scanner { internal struct ScanData { public int ShipValue; public int OutdoorValue; public int IndoorValue; public int ShipScrapAmount; public int OutdoorScrapAmount; public int IndoorScrapAmount; public bool FoundEggs; public bool FoundHives; public ScanData() { ShipValue = 0; OutdoorValue = 0; IndoorValue = 0; ShipScrapAmount = 0; OutdoorScrapAmount = 0; IndoorScrapAmount = 0; FoundEggs = false; FoundHives = false; } } internal class Scan { private static ScanData RunScan() { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) GrabbableObject[] array = Object.FindObjectsOfType(); ScanData result = new ScanData(); GrabbableObject[] array2 = array; foreach (GrabbableObject val in array2) { if (val.itemProperties.itemName == "Body") { continue; } if (val.itemProperties.itemName == "Egg" && !val.isInShipRoom) { result.FoundEggs = true; } if (val.itemProperties.itemName == "Hive" && !val.isInShipRoom) { result.FoundHives = true; } if (val.itemProperties.isScrap && !val.isInShipRoom) { if (((Component)val).transform.position.y < -80f) { result.IndoorValue += val.scrapValue; result.IndoorScrapAmount++; } else { result.OutdoorValue += val.scrapValue; result.OutdoorScrapAmount++; } } else if (val.itemProperties.isScrap) { result.ShipValue += val.scrapValue; result.ShipScrapAmount++; } } return result; } public static void Initialize(Terminal t) { if (!((NetworkBehaviour)StartOfRound.Instance).IsHost) { return; } TerminalCommand scanCommand = new TerminalCommand("scan"); scanCommand.AddState("default", delegate(string[] args) { ScanData scanData = RunScan(); if (args.Length > 1 && OverworkedTerminal.Match(args[1], "-share")) { SellingModule.SendMessage($"Terminal/Scan: {scanData.IndoorScrapAmount} {scanData.OutdoorScrapAmount}"); } scanCommand.Finish(); return "The ship scanners have detected the following:\n\n" + $"* Ship value: ${scanData.ShipValue} ({scanData.ShipScrapAmount} items)\n" + $"* Outdoor value: ${scanData.OutdoorValue} ({scanData.OutdoorScrapAmount} items)\n" + $"* Indoor value: ${scanData.IndoorValue} ({scanData.IndoorScrapAmount} items)" + (scanData.FoundEggs ? "\n\nA giant bird like creature seems to have nested on the exomoon." : "") + (scanData.FoundHives ? "\n\nDangerous insect life seems to live in harmony with the ecosystem." : "") + $"\n\nFor a total of {scanData.IndoorScrapAmount + scanData.OutdoorScrapAmount} items outside."; }); OverworkedTerminal.AddCommand(scanCommand); } } } namespace Overworked.Core.Placement { [HarmonyPatch(typeof(StartOfRound))] internal class ItemPlacement { private static readonly Dictionary placements = new Dictionary { { "Pro-flashlight", new Vector3(7.7134f, 1f, -14.1152f) }, { "Flashlight", new Vector3(7.7134f, 0.3565f, -14.1152f) }, { "Shovel", new Vector3(5.7842f, 0.3817f, -14.9624f) }, { "Lockpicker", new Vector3(6.6094f, 0.3796f, -14.103f) }, { "Weed killer", new Vector3(5.3645f, 0.7417f, -14.1853f) }, { "Spray paint", new Vector3(4.6839f, 0.3617f, -13.9803f) }, { "Walkie-talkie", new Vector3(4.1293f, 0.3417f, -14.1254f) }, { "Stun grenade", new Vector3(3.4229f, 0.3009f, -13.9947f) }, { "Extension ladder", new Vector3(7.8912f, 0.396f, -13.0898f) }, { "Belt bag", new Vector3(6.547f, 0.6398f, -12.9742f) }, { "Jetpack", new Vector3(5.6698f, 0.4417f, -13.0838f) }, { "Key", new Vector3(4.0051f, 0.3117f, -13.084f) }, { "Shotgun", new Vector3(4.7607f, 0.323f, -15.0969f) }, { "Ammo", new Vector3(4.1876f, 0.4307f, -15.0332f) }, { "Kitchen knife", new Vector3(5.0984f, 0.3517f, -13.1254f) } }; public static void ReplaceItems() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) GrabbableObject[] array = Object.FindObjectsOfType(); GrabbableObject[] array2 = array; foreach (GrabbableObject val in array2) { if (placements.TryGetValue(val.itemProperties.itemName, out var value)) { ((Component)val).gameObject.transform.position = value; } } } [HarmonyPatch("LoadShipGrabbableItems")] [HarmonyPostfix] private static void LoadShipGrabbableItems_Postfix(StartOfRound __instance) { ReplaceItems(); } } } namespace Overworked.Core.Levels { [HarmonyPatch(typeof(RoundManager))] internal class LevelLoading { public static void ApplyLevelData(SelectableLevel newLevel) { string planetName = newLevel.PlanetName; string text = planetName; string text2 = text; if (!(text2 == "20 Adamance")) { if (text2 == "68 Artifice") { newLevel.maxScrap = 37; newLevel.minScrap = 31; } } else { newLevel.maxScrap = 18; newLevel.minScrap = 16; } foreach (SpawnableEnemyWithRarity enemy in newLevel.Enemies) { string enemyName = enemy.enemyType.enemyName; if (enemyName == "Cadaver Growths" && planetName == "20 Adamance") { enemy.rarity = 0; } } } [HarmonyPatch("LoadNewLevel")] [HarmonyPrefix] private static void LoadNewLevel_Prefix(ref SelectableLevel newLevel) { ApplyLevelData(newLevel); } } } namespace Overworked.Core.CustomTerminal { internal class TerminalCommand { public bool ShouldUnfocus = false; public string Keyword { get; } public string CommandState { get; private set; } = "default"; public Dictionary> RegisteredStates { get; } = new Dictionary>(); public TerminalCommand(string keyword) { Keyword = keyword.ToLower(); } public void AddState(string stateName, Func newState) { RegisteredStates[stateName] = newState; } public void MoveTo(string state) { if (RegisteredStates.ContainsKey(state)) { CommandState = state; } } public void Finish() { ShouldUnfocus = true; CommandState = "default"; } } [HarmonyPatch(typeof(Terminal))] internal class OverworkedTerminal { private static List _commands = new List(); private static TerminalNode _resultNode = new TerminalNode(); private static TerminalCommand _focusedCommand; public static void AddCommand(TerminalCommand newCommand) { _commands.Add(newCommand); } public static bool Match(string input, string compare) { if (input.Length > compare.Length) { return false; } return compare.StartsWith(input, StringComparison.OrdinalIgnoreCase); } [HarmonyPatch("ParsePlayerSentence")] [HarmonyPrefix] private static bool ParsePlayerSentence(Terminal __instance, ref TerminalNode __result) { string text = __instance.screenText.text.Substring(__instance.screenText.text.Length - __instance.textAdded); string[] array = text.Split(" ", StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0) { return true; } string firstArgument = array[0].ToLower(); if (_focusedCommand == null) { _focusedCommand = _commands.FirstOrDefault((TerminalCommand c) => c.Keyword == firstArgument); } if (_focusedCommand == null) { return true; } Func func = _focusedCommand.RegisteredStates[_focusedCommand.CommandState]; string text2 = func(array); if (_focusedCommand.ShouldUnfocus) { _focusedCommand.ShouldUnfocus = false; _focusedCommand = null; } _resultNode.displayText = text2 ?? "OverworkedTerminal: No data was returned from your command."; TerminalNode resultNode = _resultNode; resultNode.displayText += "\n\n"; _resultNode.clearPreviousText = true; __result = _resultNode; return false; } [HarmonyPatch("Start")] [HarmonyPostfix] private static void Start_Prefix(Terminal __instance) { _commands.Clear(); SellingModule.Initialize(__instance); Scan.Initialize(__instance); } } } namespace Overworked.Core.AlwaysGrab { [HarmonyPatch(typeof(GrabbableObject))] internal class ObjectGrab { [HarmonyPatch("Start")] [HarmonyPostfix] private static void Start_Postfix(GrabbableObject __instance) { __instance.itemProperties.canBeGrabbedBeforeGameStart = true; } } }