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";
}
}