Decompiled source of ScanPlus v1.1.1

plugins/ScanPlus.dll

Decompiled 2 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
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.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AidanTweedy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Ship scanner mod for Lethal Company")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyInformationalVersion("1.1.1+890b1d0edc0e47376af3b78495ded869b1a1641d")]
[assembly: AssemblyProduct("ScanPlus")]
[assembly: AssemblyTitle("ScanPlus")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/AidanTweedy/scanplus")]
[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 ScanPlus
{
	public class ConfigManager
	{
		private ConfigEntry<int> _detailLevel;

		private ConfigEntry<bool> _shipUpgrade;

		private ConfigEntry<int> _upgradePrice;

		private ConfigFile _config;

		public int DetailLevel => _detailLevel.Value;

		public bool ShipUpgrade => _shipUpgrade.Value;

		public int UpgradePrice => _upgradePrice.Value;

		public ConfigManager(ConfigFile config)
		{
			_config = config;
		}

		public void LoadConfigurations()
		{
			_detailLevel = _config.Bind<int>("DETAIL", "DetailLevel", 2, "Life Scan Detail -> | 0 = LOW | 1 = MEDIUM | 2 = HIGH | 3 = EXCESSIVE");
			_shipUpgrade = _config.Bind<bool>("PREFERENCES", "ShipUpgrade", true, "Enable Ship Upgrade -> | false = No | true = Yes");
			_upgradePrice = _config.Bind<int>("PREFERENCES", "UpgradePrice", 300, "Ship Scanner Upgrade Cost");
		}
	}
	[HarmonyPatch(typeof(Terminal))]
	public class TFCompatibility
	{
		[HarmonyPostfix]
		[HarmonyPatch("TextPostProcess")]
		public static void TextPostProcessPrefixPostFix(string modifiedDisplayText, TerminalNode node, Terminal __instance)
		{
			if (((Object)node).name == "ScanInfo" && ScanPlus.Instance._scanner.UseUpgradedScan() && !__instance.currentText.ToLower().Contains("threat"))
			{
				__instance.currentText += ScanPlus.Instance._scanner.BuildEnemyString();
			}
		}
	}
	public class Scanner
	{
		private ConfigManager ConfigManager;

		private UnlockableManager UnlockableManager;

		internal const string DefaultString = "\nNo life detected.\n\n";

		public static Scanner Instance { get; private set; }

		public Scanner(ConfigManager _configManager, UnlockableManager _unlockableManager)
		{
			Instance = this;
			ConfigManager = _configManager;
			UnlockableManager = _unlockableManager;
			ScanPlus.Harmony.PatchAll(typeof(Scanner));
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")]
		public static void ParsePlayerSentence(ref TerminalNode __result)
		{
			if (((Object)__result).name == "ScanInfo" && Instance.UseUpgradedScan())
			{
				string text = "\n";
				__result.displayText = __result.displayText.Split(text)[0] + text + Instance.BuildEnemyString();
			}
		}

		public string BuildEnemyString()
		{
			List<IGrouping<string, EnemyAI>> list = (from ai in RoundManager.Instance.SpawnedEnemies
				where ((Component)ai).GetComponentInChildren<ScanNodeProperties>() != null
				group ai by ai.enemyType.enemyName into g
				orderby g.Key
				select g).ToList();
			if (list.Count == 0)
			{
				return "\nNo life detected.\n\n";
			}
			int num = list.SelectMany((IGrouping<string, EnemyAI> group) => group).Count();
			float num2 = (from ai in list.SelectMany((IGrouping<string, EnemyAI> @group) => @group)
				where !ai.enemyType.isDaytimeEnemy
				select ai).Sum(delegate(EnemyAI ai)
			{
				if ((Object)(object)ai?.enemyType == (Object)null)
				{
					return 0f;
				}
				FieldInfo field = ((object)ai.enemyType).GetType().GetField("PowerLevel");
				return (!(field != null)) ? 0f : Convert.ToSingle(field.GetValue(ai.enemyType));
			});
			int num3 = RoundManager.Instance.currentLevel.maxEnemyPowerCount + RoundManager.Instance.currentLevel.maxOutsideEnemyPowerCount;
			string text = BuildColoredPercentage(num2 / (float)num3);
			string nextSpawn = GetNextSpawn();
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append('\n');
			switch (ConfigManager.DetailLevel)
			{
			case 0:
				stringBuilder.Append("Threat level: " + text);
				break;
			case 1:
				stringBuilder.Append($"Threat level: {text}\n\n{num} lifeforms detected, totalling a threat level of {(int)num2}.");
				break;
			case 2:
				stringBuilder.Append($"Threat level: {text}\n\n{num} lifeforms detected, totalling a threat level of {(int)num2}.\n\nLife detected:");
				foreach (IGrouping<string, EnemyAI> item in list)
				{
					stringBuilder.AppendLine($"\n  {item.Key}: {item.Count()}");
				}
				break;
			case 3:
				stringBuilder.Append($"Threat level: {text}\n\n{num} lifeforms detected, totalling a threat level of {(int)num2}.\n\nLife detected:");
				foreach (IGrouping<string, EnemyAI> item2 in list)
				{
					stringBuilder.AppendLine($"\n  {item2.Key}: {item2.Count()}");
				}
				stringBuilder.AppendLine("\nNext spawn: " + nextSpawn);
				break;
			}
			stringBuilder.AppendLine();
			return stringBuilder.ToString();
		}

		private static string BuildColoredPercentage(float value)
		{
			float num = Math.Max(0f, Math.Min(1f, value));
			int num2;
			int num3;
			if ((double)num <= 0.5)
			{
				num2 = (int)(num * 2f * 255f);
				num3 = 255;
			}
			else
			{
				num2 = 255;
				num3 = (int)((1.0 - (double)num) * 2.0 * 255.0);
			}
			string text = $"#{num2:X2}{num3:X2}00";
			string text2 = (num * 100f).ToString("0.##") + "%";
			return "<color=" + text + ">" + text2 + "</color>";
		}

		private static string GetNextSpawn()
		{
			if ((float)(RoundManager.Instance.enemySpawnTimes.Any((int t) => (float)t > RoundManager.Instance.timeScript.currentDayTime) ? RoundManager.Instance.enemySpawnTimes.Min() : (-1)) - RoundManager.Instance.timeScript.currentDayTime >= 60f)
			{
				return "Incoming";
			}
			return "Unknown";
		}

		public bool UseUpgradedScan()
		{
			if (!ConfigManager.ShipUpgrade)
			{
				return true;
			}
			if (UnlockableManager.IsScannerUnlocked())
			{
				return true;
			}
			return false;
		}
	}
	[BepInPlugin("ScanPlus", "ScanPlus", "1.1.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class ScanPlus : BaseUnityPlugin
	{
		internal static ManualLogSource Log = null;

		internal static Harmony Harmony = new Harmony("ScanPlus");

		private ConfigManager _configManager;

		private UnlockableManager _unlockableManager;

		internal Scanner _scanner;

		public static ScanPlus Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			_configManager = new ConfigManager(((BaseUnityPlugin)this).Config);
			_configManager.LoadConfigurations();
			_unlockableManager = new UnlockableManager(_configManager);
			_scanner = new Scanner(_configManager, _unlockableManager);
			if (Chainloader.PluginInfos.ContainsKey("TerminalFormatter"))
			{
				Harmony.PatchAll(typeof(TFCompatibility));
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"ScanPlus is loaded");
		}
	}
	public class UnlockableManager
	{
		private ConfigManager ConfigManager;

		private const string UpgradeName = "Infrared Scanner";

		private const string UpgradeInfo = "\nUpgrades the ship's scanner with an infrared sensor, allowing for the detection of lifeforms present on the current moon.\n";

		private int UpgradePrice;

		internal UnlockableItem ScanUpgrade = new UnlockableItem
		{
			unlockableName = "Infrared Scanner",
			spawnPrefab = false,
			alwaysInStock = true,
			prefabObject = null,
			unlockableType = 1,
			IsPlaceable = false,
			maxNumber = 1,
			canBeStored = false,
			alreadyUnlocked = false
		};

		public static UnlockableManager Instance { get; private set; }

		public UnlockableManager(ConfigManager _configManager)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			Instance = this;
			ConfigManager = _configManager;
			if (ConfigManager.ShipUpgrade)
			{
				ScanPlus.Log.LogInfo((object)"ScanPlus: adding scanner to store");
				ScanPlus.Harmony.PatchAll(typeof(UnlockableManager));
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Terminal), "Awake")]
		public static void TerminalAwake(Terminal __instance)
		{
			try
			{
				Instance?.AddScannerToStore(__instance);
			}
			catch (Exception arg)
			{
				ScanPlus.Log.LogInfo((object)string.Format("{0}: error occurred adding scanner to store:\n{1}", "ScanPlus", arg));
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Terminal), "TextPostProcess")]
		public static void TextPostProcess(ref string modifiedDisplayText, TerminalNode node)
		{
			try
			{
				if (modifiedDisplayText.Contains("[buyableItemsList]") && modifiedDisplayText.Contains("[unlockablesSelectionList]"))
				{
					int num = modifiedDisplayText.IndexOf(":");
					string value = string.Format("\n* {0}    //    Price: ${1}", "Infrared Scanner", Instance.UpgradePrice);
					modifiedDisplayText = modifiedDisplayText.Insert(num + 1, value);
				}
			}
			catch (Exception ex)
			{
				ScanPlus.Log.LogError((object)ex);
			}
		}

		private static TerminalKeyword CreateKeyword(string word, TerminalKeyword defaultVerb)
		{
			TerminalKeyword obj = ScriptableObject.CreateInstance<TerminalKeyword>();
			((Object)obj).name = word;
			obj.word = word;
			obj.isVerb = false;
			obj.accessTerminalObjects = false;
			obj.defaultVerb = defaultVerb;
			return obj;
		}

		public void AddScannerToStore(Terminal terminal)
		{
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_027e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0287: Expected O, but got Unknown
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cb: Expected O, but got Unknown
			//IL_0359: Unknown result type (might be due to invalid IL or missing references)
			//IL_035e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Expected O, but got Unknown
			//IL_0390: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			//IL_039d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Expected O, but got Unknown
			int num = -1;
			UnlockablesList unlockablesList = StartOfRound.Instance.unlockablesList;
			if (unlockablesList.unlockables.FindIndex((UnlockableItem unlockable) => unlockable.unlockableName == "Infrared Scanner") == -1)
			{
				TerminalKeyword val = terminal.terminalNodes.allKeywords.First((TerminalKeyword keyword) => keyword.word == "buy");
				TerminalNode result = val.compatibleNouns[0].result.terminalOptions[1].result;
				TerminalKeyword val2 = terminal.terminalNodes.allKeywords.First((TerminalKeyword keyword) => keyword.word == "info");
				TerminalKeyword val3 = CreateKeyword("Infrared Scanner".ToLowerInvariant().Replace(" ", "") ?? "", val);
				UpgradePrice = ConfigManager.UpgradePrice;
				unlockablesList.unlockables.Capacity++;
				unlockablesList.unlockables.Add(ScanUpgrade);
				num = unlockablesList.unlockables.FindIndex((UnlockableItem unlockable) => unlockable.unlockableName == "Infrared Scanner");
				TerminalNode val4 = ScriptableObject.CreateInstance<TerminalNode>();
				((Object)val4).name = "Infrared Scanner".Replace(" ", "-") + "BuyNode2";
				val4.displayText = "Ordered Infrared Scanner! Your new balance is [playerCredits].\n\n";
				val4.clearPreviousText = true;
				val4.maxCharactersToType = 15;
				val4.buyItemIndex = -1;
				val4.shipUnlockableID = num;
				val4.buyUnlockable = true;
				val4.creatureName = "Infrared Scanner";
				val4.isConfirmationNode = false;
				val4.itemCost = UpgradePrice;
				TerminalNode val5 = ScriptableObject.CreateInstance<TerminalNode>();
				((Object)val5).name = "Infrared Scanner".Replace(" ", "-") + "BuyNode1";
				val5.displayText = "You have requested to order Infrared Scanner.\nTotal cost of item: [totalCost].\n\nPlease CONFIRM or DENY.\n\n";
				val5.clearPreviousText = true;
				val5.maxCharactersToType = 15;
				val5.shipUnlockableID = num;
				val5.itemCost = UpgradePrice;
				val5.creatureName = "Infrared Scanner";
				val5.overrideOptions = true;
				val5.terminalOptions = (CompatibleNoun[])(object)new CompatibleNoun[2]
				{
					new CompatibleNoun
					{
						noun = terminal.terminalNodes.allKeywords.First((TerminalKeyword keyword2) => keyword2.word == "confirm"),
						result = val4
					},
					new CompatibleNoun
					{
						noun = terminal.terminalNodes.allKeywords.First((TerminalKeyword keyword2) => keyword2.word == "deny"),
						result = result
					}
				};
				string displayText = "\nUpgrades the ship's scanner with an infrared sensor, allowing for the detection of lifeforms present on the current moon.\n";
				TerminalNode val6 = ScriptableObject.CreateInstance<TerminalNode>();
				((Object)val6).name = "Infrared Scanner".Replace(" ", "-") + "InfoNode";
				val6.displayText = displayText;
				val6.clearPreviousText = true;
				val6.maxCharactersToType = 25;
				List<TerminalKeyword> list = terminal.terminalNodes.allKeywords.ToList();
				list.Add(val3);
				terminal.terminalNodes.allKeywords = list.ToArray();
				List<CompatibleNoun> list2 = val.compatibleNouns.ToList();
				list2.Add(new CompatibleNoun
				{
					noun = val3,
					result = val5
				});
				val.compatibleNouns = list2.ToArray();
				List<CompatibleNoun> list3 = val2.compatibleNouns.ToList();
				list3.Add(new CompatibleNoun
				{
					noun = val3,
					result = val6
				});
				val2.compatibleNouns = list3.ToArray();
				ScanPlus.Log.LogInfo((object)"ScanPlus: successfully added Infrared Scanner to the store.");
			}
		}

		public bool IsScannerUnlocked()
		{
			return ScanUpgrade?.hasBeenUnlockedByPlayer ?? false;
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "ScanPlus";

		public const string PLUGIN_NAME = "ScanPlus";

		public const string PLUGIN_VERSION = "1.1.1";
	}
}