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 LCDrone v0.6.28
plugins/LCDrone/LCDrone.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; 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.Configuration; using BepInEx.Logging; using Dawn; using DunGen; using DunGen.Graph; using Dusk; using GameNetcodeStuff; using HarmonyLib; using LCDrone.Cargo; using LCDrone.Configuration; using LCDrone.Core; using LCDrone.Core.Behaviors; using LCDrone.Core.Cargo; using LCDrone.Core.Commands; using LCDrone.Core.Mapping; using LCDrone.Core.Modules; using LCDrone.Core.Navigation; using LCDrone.Core.Save; using LCDrone.Core.TerminalScreen; using LCDrone.Core.World; using LCDrone.Doors; using LCDrone.Drone; using LCDrone.Mapping; using LCDrone.Navigation; using LCDrone.NetcodePatcher; using LCDrone.Patches; using LCDrone.TerminalScreen; using Microsoft.CodeAnalysis; using PathfindingLib.API.SmartPathfinding; using PathfindingLib.Utilities; using TMPro; using Unity.Collections; using Unity.Netcode; using Unity.Netcode.Components; using UnityEngine; using UnityEngine.AI; using UnityEngine.Experimental.AI; using UnityEngine.SceneManagement; using UnityEngine.UI; [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("LCDrone")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.6.28.0")] [assembly: AssemblyInformationalVersion("0.6.28+97897d28961d118a74e3b1e9132c6158966b9ed1")] [assembly: AssemblyProduct("LCDrone")] [assembly: AssemblyTitle("LCDrone")] [assembly: InternalsVisibleTo("LCDrone.Tests")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.6.28.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 LCDrone { [BepInPlugin("LCDrone", "LCDrone", "0.6.28")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Logger = null; private static readonly Harmony harmony = new Harmony("LCDrone"); internal static PluginConfig BoundConfig { get; private set; } = null; private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; BoundConfig = new PluginConfig(((BaseUnityPlugin)this).Config); InitializeNetcode(); ApplyPatches(); DroneLog.Initialize(); DroneSelection.Initialize(); MapLabels.Initialize(); RegisterTerminalCommands(); Logger.LogInfo((object)"Plugin [LCDrone] is loaded!"); } private static void ApplyPatches() { Type[] array = new Type[45] { typeof(RoundManagerPatches), typeof(RoundManagerExitIdPatches), typeof(StartOfRoundPatches), typeof(GameNetworkManagerSavePatches), typeof(ManualCameraRendererPatches), typeof(TerminalPatches), typeof(TerminalDisablePatches), typeof(HoarderBugPatches), typeof(DroneDamagePatches), typeof(ForestGiantDroneAwarenessPatches), typeof(ForestGiantDroneAwarenessCleanupPatches), typeof(MouthDogDroneCollisionPatch), typeof(MouthDogDroneCollisionCleanupPatch), typeof(MouthDogDroneNoisePatch), typeof(ThumperDroneChasePatch), typeof(ThumperDroneChaseCleanupPatch), typeof(ThumperDroneOwnershipCleanupPatch), typeof(ThumperDroneCollisionPatch), typeof(CoilHeadDroneVisionPatch), typeof(BrackenDroneVisionPatch), typeof(SporeLizardDroneDefensePatch), typeof(SporeLizardDroneDefenseCleanupPatch), typeof(HygrodereDronePatches), typeof(HygrodereDroneSlowPatch), typeof(HygrodereDroneCleanupPatch), typeof(SnareFleaDronePatches), typeof(BarberDroneCollisionPatch), typeof(BarberDroneCleanupPatch), typeof(NutcrackerDronePatches), typeof(NutcrackerDroneShotPatch), typeof(NutcrackerDroneCleanupPatch), typeof(ManticoilDronePatches), typeof(RoamingLocustDronePatches), typeof(CircuitBeeDroneHivePatch), typeof(CircuitBeeDroneCollisionPatch), typeof(FeioparDroneVisionPatch), typeof(FeioparDroneVisionCleanupPatch), typeof(FeioparDroneNoisePatch), typeof(KidnapperFoxDroneVisionPatch), typeof(KidnapperFoxDroneVisionCleanupPatch), typeof(CoilHeadDroneVisionCleanupPatch), typeof(BrackenDroneVisionCleanupPatch), typeof(RoamingLocustDroneCleanupPatch), typeof(CircuitBeeDroneHiveCleanupPatch), typeof(DroneShopPatches) }; Type[] array2 = array; foreach (Type type in array2) { try { harmony.CreateClassProcessor(type).Patch(); if (type == typeof(DroneShopPatches)) { DroneShopPatches.SetHooksInstalled(installed: true); } } catch (Exception arg) { if (type == typeof(DroneShopPatches)) { DroneShopPatches.SetHooksInstalled(installed: false); } Logger.LogError((object)$"Failed to apply the {type.Name} patches, some features won't work: {arg}"); } } } private static void RegisterTerminalCommands() { try { DroneTerminalCommand.Register(); } catch (Exception arg) { Logger.LogError((object)$"Failed to register the drone terminal command, the drone screen won't open: {arg}"); } } private static void InitializeNetcode() { Type[] array; try { array = Assembly.GetExecutingAssembly().GetTypes(); } catch (ReflectionTypeLoadException ex) { array = ex.Types.Where((Type type2) => type2 != null).ToArray(); } Type[] array2 = array; foreach (Type type in array2) { if (type.ContainsGenericParameters) { continue; } MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.IsDefined(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false) && !methodInfo.ContainsGenericParameters && methodInfo.GetParameters().Length == 0) { try { methodInfo.Invoke(null, null); } catch (Exception arg) { Logger.LogError((object)$"Netcode initializer {type.FullName}.{methodInfo.Name} threw an exception: {arg}"); } } } } } [Conditional("DEBUG")] internal static void LogIfDebugBuild(string text) { Logger.LogInfo((object)text); } } public static class PluginInfo { public const string PLUGIN_GUID = "LCDrone"; public const string PLUGIN_NAME = "LCDrone"; public const string PLUGIN_VERSION = "0.6.28"; } } namespace LCDrone.TerminalScreen { internal static class DroneScreen { private const int MaxCharactersToType = 64; private const int ScrollFrames = 5; private const float ScrollBottom = 0f; private const float ScrollTop = 1f; private const float ScrolledUpThreshold = 0.05f; private const int HelpNodeIndex = 13; private const string ViewVerb = "view"; private const string MonitorNoun = "monitor"; private static Terminal? activeTerminal; private static Terminal? pendingTerminal; private static TerminalNode? screenNode; private static TerminalNode? monitorNode; private static int batchDepth; private static bool redrawPending; private static bool redrawPendingScrolls; private static FieldRef<Terminal, Coroutine?>? scrollCoroutineRef; private static bool scrollCoroutineRefFailed; internal static DroneController? CurrentDrone => DroneSelection.Current; internal static Terminal? AudioTerminal { get { if (!((Object)(object)activeTerminal != (Object)null) || !activeTerminal.terminalInUse) { return null; } return activeTerminal; } } internal static bool IsActive(Terminal terminal) { if ((Object)(object)activeTerminal != (Object)null) { return (Object)(object)activeTerminal == (Object)(object)terminal; } return false; } internal static void OnDroneCommand(Terminal terminal, TerminalNode node) { pendingTerminal = terminal; } internal static void OnNodeLoaded(Terminal terminal, TerminalNode node) { if ((Object)(object)pendingTerminal != (Object)null && (Object)(object)pendingTerminal == (Object)(object)terminal && ((Object)(object)DroneTerminalCommand.ResultNode == (Object)null || (Object)(object)node == (Object)(object)DroneTerminalCommand.ResultNode)) { pendingTerminal = null; Enter(terminal); } else if (IsActive(terminal) && (Object)(object)terminal.currentNode != (Object)(object)screenNode) { Close("another terminal node was loaded"); } } internal static void Leave(Terminal terminal, string reason) { bool flag = activeTerminal == terminal || pendingTerminal == terminal; bool flag2 = (activeTerminal != null && (Object)(object)activeTerminal == (Object)null) || (pendingTerminal != null && (Object)(object)pendingTerminal == (Object)null); if (flag || flag2) { Close(reason); } } internal static void Submit(Terminal terminal) { if (!terminal.terminalInUse) { return; } if (terminal.textAdded == 0) { Focus(terminal); return; } string typedText = DroneScreenText.GetTypedText(terminal.screenText.text, terminal.textAdded); batchDepth++; try { terminal.textAdded = 0; RequestRedraw(scroll: true); HandleLine(terminal, typedText); } finally { batchDepth--; if (batchDepth == 0 && redrawPending) { Redraw(redrawPendingScrolls); } } Focus(terminal); } internal static void ScrollToBottom(Terminal terminal) { ScrollTo(terminal, 0f); } private static void HandleLine(Terminal terminal, string typed) { string line; string[] args; DroneScreenInputKind droneScreenInputKind = DroneScreenInput.Classify(typed, out line, out args); switch (droneScreenInputKind) { case DroneScreenInputKind.Empty: return; case DroneScreenInputKind.Exit: Exit(terminal); return; default: AddLocalLine(DroneLogKind.Command, GetLocalPlayerName() + "> " + line); break; case DroneScreenInputKind.ToDrone: case DroneScreenInputKind.Command: break; } switch (droneScreenInputKind) { case DroneScreenInputKind.Help: AddLocalLines(DroneScreenText.FormatHelp(DroneCommandCatalog.BuiltIn)); return; case DroneScreenInputKind.HelpDebug: AddLocalLines(DroneScreenText.FormatDebugHelp(DroneCommandCatalog.BuiltIn)); return; case DroneScreenInputKind.HelpScreen: AddLocalLines(DroneScreenText.FormatScreenHelp()); return; case DroneScreenInputKind.Drones: ListDrones(args); return; case DroneScreenInputKind.Select: Select(args); return; case DroneScreenInputKind.Release: Release(args); return; case DroneScreenInputKind.Monitor: ToggleMonitor(terminal); return; case DroneScreenInputKind.Floor: SelectFloor(args); return; case DroneScreenInputKind.Switch: SwitchMonitor(args); return; case DroneScreenInputKind.Focus: FocusMonitor(args); return; case DroneScreenInputKind.ToDrone: SendToDrone(line); return; } DroneController currentDrone = CurrentDrone; if ((Object)(object)currentDrone == (Object)null) { AddLocalLine(DroneLogKind.Command, GetLocalPlayerName() + "> " + line); AddLocalLine(DroneLogKind.Error, "There is no drone to send that to."); } else { currentDrone.SubmitCommand(line); } } private static void SendToDrone(string line) { DroneController drone; if (!DroneScreenInput.TryParseDronePrefix(line, out int droneId, out string command)) { AddLocalLine(DroneLogKind.Command, GetLocalPlayerName() + "> " + line); AddLocalLine(DroneLogKind.Error, "Usage: d<n> <command> (or drone <n> <command>)"); } else if (!DroneRegistry.TryGet(droneId, out drone) || (Object)(object)drone == (Object)null) { AddLocalLine(DroneLogKind.Command, GetLocalPlayerName() + "> " + line); AddLocalLine(DroneLogKind.Error, $"There is no drone {droneId}."); } else { drone.SubmitCommand(command); } } private static void ToggleMonitor(Terminal terminal) { TerminalNode val = GetMonitorNode(terminal); if ((Object)(object)val == (Object)null || (Object)(object)val.displayTexture == (Object)null) { AddLocalLine(DroneLogKind.Error, "Couldn't find the monitor view."); return; } bool flag = IsMonitorShown(terminal); terminal.LoadTerminalImage(val); if (!flag && !IsMonitorShown(terminal)) { AddLocalLine(DroneLogKind.Info, "The map only works while the ship is landed."); } else { RequestRedraw(scroll: true); } } private static void SelectFloor(string[] args) { bool flag; string message; if (args.Length == 0) { flag = MapLabels.TryCycleFloor(out message); } else { if (args.Length != 1 || !int.TryParse(args[0], NumberStyles.None, CultureInfo.InvariantCulture, out var result)) { AddLocalLine(DroneLogKind.Error, "Usage: floor [n] - cycle floors or select floor n."); return; } flag = MapLabels.TrySelectFloor(result, out message); } AddLocalLine(flag ? DroneLogKind.Info : DroneLogKind.Error, message); } private static void SwitchMonitor(string[] args) { StartOfRound instance = StartOfRound.Instance; ManualCameraRenderer val = (((Object)(object)instance != (Object)null) ? instance.mapScreen : null); if ((Object)(object)val == (Object)null || val.radarTargets == null || val.radarTargets.Count == 0) { AddLocalLine(DroneLogKind.Error, "The ship monitor isn't available."); return; } if (args.Length == 0) { MapLabels.ResetFloorSelection(); val.SwitchRadarTargetForward(true); return; } string text = string.Join(" ", args); string[] names = val.radarTargets.Select((TransformAndName target) => target?.name).ToArray(); int num = MonitorTargets.Find(names, text); if (num < 0) { AddLocalLine(DroneLogKind.Error, "There is no monitor target '" + text + "'."); return; } MapLabels.ResetFloorSelection(); val.SwitchRadarTargetAndSync(num); } private static void FocusMonitor(string[] args) { if (args.Length != 0) { AddLocalLine(DroneLogKind.Error, "'focus' takes no arguments."); return; } DroneController currentDrone = CurrentDrone; if ((Object)(object)currentDrone == (Object)null) { AddLocalLine(DroneLogKind.Error, "There is no drone to focus."); return; } StartOfRound instance = StartOfRound.Instance; ManualCameraRenderer val = (((Object)(object)instance != (Object)null) ? instance.mapScreen : null); if ((Object)(object)val == (Object)null || val.radarTargets == null || val.radarTargets.Count == 0) { AddLocalLine(DroneLogKind.Error, "The ship monitor isn't available."); return; } string[] names = val.radarTargets.Select((TransformAndName target) => target?.name).ToArray(); int num = MonitorTargets.FindDrone(names, currentDrone.DroneId); if (num < 0) { AddLocalLine(DroneLogKind.Error, $"Drone {currentDrone.DroneId} isn't on the ship monitor."); return; } MapLabels.ResetFloorSelection(); val.SwitchRadarTargetAndSync(num); AddLocalLine(DroneLogKind.Info, $"Focused the ship monitor on Drone {currentDrone.DroneId}."); } private static bool IsMonitorShown(Terminal terminal) { if ((Object)(object)terminal.displayingPersistentImage != (Object)null && (Object)(object)terminal.terminalImage != (Object)null) { return ((Behaviour)terminal.terminalImage).enabled; } return false; } private static TerminalNode? GetMonitorNode(Terminal terminal) { if ((Object)(object)monitorNode != (Object)null) { return monitorNode; } TerminalKeyword[] array = (((Object)(object)terminal.terminalNodes != (Object)null) ? terminal.terminalNodes.allKeywords : null); if (array == null) { return null; } TerminalKeyword[] array2 = array; foreach (TerminalKeyword val in array2) { if ((Object)(object)val == (Object)null || !val.isVerb || val.word != "view" || val.compatibleNouns == null) { continue; } CompatibleNoun[] compatibleNouns = val.compatibleNouns; foreach (CompatibleNoun val2 in compatibleNouns) { if (val2 != null && (Object)(object)val2.noun != (Object)null && val2.noun.word == "monitor" && (Object)(object)val2.result != (Object)null) { monitorNode = val2.result; return monitorNode; } } } return null; } private static void HideMonitor(Terminal terminal) { Texture displayingPersistentImage = terminal.displayingPersistentImage; if (!((Object)(object)displayingPersistentImage == (Object)null)) { terminal.displayingPersistentImage = null; if ((Object)(object)terminal.terminalImage != (Object)null && (Object)(object)terminal.terminalImage.texture == (Object)(object)displayingPersistentImage) { ((Behaviour)terminal.terminalImage).enabled = false; } } } private static void ListDrones(string[] args) { if (args.Length != 0) { AddLocalLine(DroneLogKind.Error, "'drones' takes no arguments."); return; } DroneController[] array = (from drone in DroneRegistry.All where (Object)(object)drone != (Object)null orderby drone.DroneId select drone).ToArray(); if (array.Length == 0) { AddLocalLine(DroneLogKind.Info, "No drones."); return; } DroneController[] array2 = array; foreach (DroneController droneController in array2) { AddLocalLine(DroneLogKind.Info, DroneScreenText.FormatDroneListLine(droneController.DroneId, droneController.ActiveBehaviorName, GetLockText(droneController), droneController.Health, droneController.MaxHealth, droneController.IsDisabled)); } } private static void Select(string[] args) { if (!DroneScreenInput.TryParseDroneNumber(args, out var droneId)) { AddLocalLine(DroneLogKind.Error, "Usage: select <n|d<n>>"); return; } if (!DroneRegistry.TryGet(droneId, out DroneController drone) || (Object)(object)drone == (Object)null) { AddLocalLine(DroneLogKind.Error, $"There is no drone {droneId}."); return; } MapLabels.ResetFloorSelection(); drone.RequestSelect(); } private static void Release(string[] args) { if (args.Length != 0) { AddLocalLine(DroneLogKind.Error, "'release' takes no arguments."); return; } DroneController droneController = DroneRegistry.All.FirstOrDefault((DroneController drone) => (Object)(object)drone != (Object)null && drone.IsLockedByLocalPlayer) ?? CurrentDrone; if ((Object)(object)droneController == (Object)null) { AddLocalLine(DroneLogKind.Info, "You don't control a drone."); } else { droneController.RequestRelease(); } } private static void Enter(Terminal terminal) { if ((Object)(object)screenNode == (Object)null) { screenNode = CreateScreenNode(); } activeTerminal = terminal; terminal.currentNode = screenNode; terminal.textAdded = 0; if ((Object)(object)terminal.terminalImage != (Object)null && ((Behaviour)terminal.terminalImage).enabled) { ((Behaviour)terminal.terminalImage).enabled = false; terminal.displayingPersistentImage = null; } Subscribe(); Redraw(scroll: true); } private static void Exit(Terminal terminal) { Close("exit"); TerminalNode val = (((Object)(object)terminal.terminalNodes != (Object)null && terminal.terminalNodes.specialNodes != null && terminal.terminalNodes.specialNodes.Count > 13) ? terminal.terminalNodes.specialNodes[13] : null); if ((Object)(object)val != (Object)null) { terminal.LoadNewNode(val); } else { Plugin.Logger.LogWarning((object)"Couldn't find the terminal's help node, showing an empty screen."); string text = (terminal.currentText = "\n\n\n"); terminal.screenText.text = text; terminal.textAdded = 0; } ScrollTo(terminal, 1f); } private static void Close(string reason) { bool flag = activeTerminal != null; Terminal val = activeTerminal; DroneAudio.CloseTerminal(); if ((Object)(object)val != (Object)null) { HideMonitor(val); } Unsubscribe(); activeTerminal = null; pendingTerminal = null; redrawPending = false; redrawPendingScrolls = false; } private static void AddLocalLine(DroneLogKind kind, string text) { DroneLog.AddLocal(kind, text); } private static void AddLocalLines(DroneLogLine[] lines) { for (int i = 0; i < lines.Length; i++) { DroneLogLine droneLogLine = lines[i]; AddLocalLine(droneLogLine.Kind, droneLogLine.Text); } } private static void RequestRedraw(bool scroll) { if (batchDepth > 0) { redrawPending = true; redrawPendingScrolls |= scroll; } else { Redraw(scroll); } } private static void Redraw(bool scroll) { redrawPending = false; redrawPendingScrolls = false; Terminal val = activeTerminal; if ((Object)(object)val == (Object)null) { if (val != null) { Close("the terminal is gone"); } } else if (!((Object)(object)val.screenText == (Object)null)) { DroneController currentDrone = CurrentDrone; string header = (((Object)(object)currentDrone == (Object)null) ? DroneScreenText.FormatHeader(0, "", "") : DroneScreenText.FormatHeader(currentDrone.DroneId, GetLockText(currentDrone), string.Format("{0} | {1}/{2} HP", currentDrone.IsDisabled ? "disabled" : DroneScreenText.FormatStatus(currentDrone.ActiveBehaviorName), currentDrone.Health, currentDrone.MaxHealth))); string text = DroneScreenText.Compose(header, DroneLog.GetLast(14), DroneRegistry.Count > 1, (Object)(object)currentDrone == (Object)null, IsMonitorShown(val)); string typedText = DroneScreenText.GetTypedText(val.screenText.text, val.textAdded); string text2 = text + typedText; bool flag = (Object)(object)val.scrollBarVertical != (Object)null && val.scrollBarVertical.value > 0.05f; val.textAdded = typedText.Length; val.currentText = text2; val.screenText.text = text2; if (scroll || !flag) { ScrollToBottom(val); } } } private static string GetLockText(DroneController drone) { return DroneScreenText.FormatLock(drone.IsLocked, drone.IsLockedByLocalPlayer, drone.LockHolderName); } private static void Focus(Terminal terminal) { if ((Object)(object)terminal.screenText != (Object)null) { terminal.screenText.ActivateInputField(); ((Selectable)terminal.screenText).Select(); } } private static void ScrollTo(Terminal terminal, float value) { if ((Object)(object)terminal.scrollBarVertical == (Object)null) { return; } terminal.scrollBarVertical.value = value; FieldRef<Terminal, Coroutine> val = GetScrollCoroutineRef(); if (val != null && ((Behaviour)terminal).isActiveAndEnabled) { ref Coroutine reference = ref val.Invoke(terminal); if (reference != null) { ((MonoBehaviour)terminal).StopCoroutine(reference); } reference = ((MonoBehaviour)terminal).StartCoroutine(KeepScrolled(terminal, value)); } } private static IEnumerator KeepScrolled(Terminal terminal, float value) { for (int i = 0; i < 5; i++) { yield return null; if ((Object)(object)terminal == (Object)null || (Object)(object)terminal.scrollBarVertical == (Object)null) { break; } terminal.scrollBarVertical.value = value; } } private static FieldRef<Terminal, Coroutine?>? GetScrollCoroutineRef() { if (scrollCoroutineRef == null && !scrollCoroutineRefFailed) { try { scrollCoroutineRef = AccessTools.FieldRefAccess<Terminal, Coroutine>("forceScrollbarCoroutine"); } catch (Exception ex) { scrollCoroutineRefFailed = true; Plugin.Logger.LogWarning((object)("Couldn't access the terminal's scroll coroutine, the drone screen may not stay scrolled down: " + ex.Message)); } } return scrollCoroutineRef; } private static TerminalNode CreateScreenNode() { TerminalNode val = ScriptableObject.CreateInstance<TerminalNode>(); ((Object)val).name = "LCDroneScreen"; ((Object)val).hideFlags = (HideFlags)61; val.displayText = ""; val.terminalEvent = ""; val.creatureName = ""; val.clearPreviousText = true; val.maxCharactersToType = 64; val.acceptAnything = false; val.overrideOptions = false; val.terminalOptions = Array.Empty<CompatibleNoun>(); return val; } private static string GetLocalPlayerName() { GameNetworkManager instance = GameNetworkManager.Instance; PlayerControllerB val = (((Object)(object)instance != (Object)null) ? instance.localPlayerController : null); if (!((Object)(object)val != (Object)null) || string.IsNullOrWhiteSpace(val.playerUsername)) { return "You"; } return val.playerUsername; } private static void Subscribe() { Unsubscribe(); DroneLog.OnLine += OnLogLine; DroneLog.LinesChanged += OnLinesChanged; DroneController.StateChanged += OnDroneStateChanged; DroneRegistry.Registered += OnDroneCameOrWent; DroneRegistry.Unregistered += OnDroneCameOrWent; DroneSelection.Changed += OnLinesChanged; } private static void Unsubscribe() { DroneLog.OnLine -= OnLogLine; DroneLog.LinesChanged -= OnLinesChanged; DroneController.StateChanged -= OnDroneStateChanged; DroneRegistry.Registered -= OnDroneCameOrWent; DroneRegistry.Unregistered -= OnDroneCameOrWent; DroneSelection.Changed -= OnLinesChanged; } private static void OnLogLine(int droneId, DroneLogKind kind, string text) { RequestRedraw(scroll: false); } private static void OnLinesChanged() { RequestRedraw(scroll: false); } private static void OnDroneCameOrWent(int droneId) { RequestRedraw(scroll: false); } private static void OnDroneStateChanged(DroneController drone) { if ((Object)(object)drone == (Object)(object)CurrentDrone) { RequestRedraw(scroll: false); } } } internal static class DroneTerminalCommand { internal const string Keyword = "drone"; private const string Namespace = "lcdrone"; private const string OtherHelpAnchor = "To scan for the number of items left on the current planet.\n\n"; private const string OtherHelpText = ">DRONE\nOpen the drone control screen.\n\n"; internal static TerminalNode? ResultNode { get; private set; } internal static void Register() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) DawnTerminalCommandInfo val = DawnLib.DefineTerminalCommand(NamespacedKey<DawnTerminalCommandInfo>.From("lcdrone", "drone_screen"), new TerminalCommandBasicInformation("LCDroneScreenCommand", "LCDrone", "Opens the drone control screen.", (ClearText)1), (Action<TerminalCommandInfoBuilder>)delegate(TerminalCommandInfoBuilder builder) { builder.SetKeywords(new List<string>(1) { "drone" }); builder.DefineEventDrivenCommand((Action<EventDrivenCommandBuilder>)delegate(EventDrivenCommandBuilder eventBuilder) { eventBuilder.SetResultNodeDisplayText((Func<string>)(() => "The drone screen couldn't be opened, see the BepInEx log.\n\n")).SetOnTerminalEvent((Action<Terminal, TerminalNode>)DroneScreen.OnDroneCommand); }); }); DawnEventDrivenCommandInfo eventDrivenCommandInfo = val.EventDrivenCommandInfo; ResultNode = ((eventDrivenCommandInfo != null) ? eventDrivenCommandInfo.ResultNode : null); if ((Object)(object)ResultNode == (Object)null) { Plugin.Logger.LogWarning((object)"DawnLib didn't create a result node for the drone command; the drone screen opens after whatever node it loads."); } new TerminalTextModifier("To scan for the number of items left on the current planet.\n\n", (IProvider<string>)(object)new SimpleProvider<string>(">DRONE\nOpen the drone control screen.\n\n")).SetNodeFromKeyword("other").SetInsertStyle((MatchInsert)2).SetIndexStyle((MatchIndex)0); } } } namespace LCDrone.Patches { [HarmonyPatch(typeof(EnemyAICollisionDetect), "OnTriggerStay")] internal static class BarberDroneCollisionPatch { private static readonly Dictionary<ClaySurgeonAI, float> lastSnipReportTimes = new Dictionary<ClaySurgeonAI, float>(); internal static void Forget(ClaySurgeonAI barber) { lastSnipReportTimes.Remove(barber); } [HarmonyPostfix] private static void OnTriggerStayPostfix(EnemyAICollisionDetect __instance, Collider other) { EnemyAI mainScript = __instance.mainScript; ClaySurgeonAI val = (ClaySurgeonAI)(object)((mainScript is ClaySurgeonAI) ? mainScript : null); if (val == null || !((NetworkBehaviour)val).IsOwner || ((EnemyAI)val).isEnemyDead || ((EnemyAI)val).stunNormalizedTimer > 0f || (Object)(object)other == (Object)null) { return; } DroneController componentInParent = ((Component)other).GetComponentInParent<DroneController>(); if (!((Object)(object)componentInParent == (Object)null) && ((Behaviour)componentInParent).isActiveAndEnabled && !componentInParent.IsDisabled && componentInParent.IsInside && !componentInParent.OnShip && componentInParent.BarberAttacksDrone) { float realtimeSinceStartup = Time.realtimeSinceStartup; if ((!lastSnipReportTimes.TryGetValue(val, out var value) || !(realtimeSinceStartup - value < 1f)) && !(Traverse.Create((object)val).Field<float>("timeSinceSnip").Value < 1f)) { lastSnipReportTimes[val] = realtimeSinceStartup; Traverse.Create((object)val).Field<float>("timeSinceSnip").Value = 0f; val.KillPlayerServerRpc(); componentInParent.ReportBarberCollision(val); } } } } [HarmonyPatch(typeof(ClaySurgeonAI), "OnDestroy")] internal static class BarberDroneCleanupPatch { [HarmonyPostfix] private static void OnDestroyPostfix(ClaySurgeonAI __instance) { BarberDroneCollisionPatch.Forget(__instance); } } [HarmonyPatch(typeof(RedLocustBees), "DoAIInterval")] internal static class CircuitBeeDroneHivePatch { private static readonly HashSet<RedLocustBees> followingDroneHive = new HashSet<RedLocustBees>(); [HarmonyPrefix] private static bool DoAIIntervalPrefix(RedLocustBees __instance) { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)__instance).IsOwner || ((EnemyAI)__instance).isEnemyDead) { return true; } if (((EnemyAI)__instance).daytimeEnemyLeaving || ((EnemyAI)__instance).stunNormalizedTimer > 0f || ((EnemyAI)__instance).inSpecialAnimation || StartOfRound.Instance.allPlayersDead) { StopFollowing(__instance, "vanilla movement state took over"); return true; } if ((Object)(object)__instance.hive == (Object)null || !CargoAnchors.IsDroneCargoAnchor(__instance.hive.parentObject)) { StopFollowing(__instance, "hive is no longer attached to a drone"); return true; } Transform parentObject = __instance.hive.parentObject; DroneController droneController = ((parentObject != null) ? ((Component)parentObject).GetComponentInParent<DroneController>() : null); if ((Object)(object)droneController == (Object)null || !((Behaviour)droneController).isActiveAndEnabled || droneController.IsDisabled || droneController.IsInside || droneController.OnShip || !droneController.CircuitBeesAttackDrone) { StopFollowing(__instance, "hive carrier is not an eligible active drone"); return true; } followingDroneHive.Add(__instance); if (((EnemyAI)__instance).currentBehaviourStateIndex != 2) { ((EnemyAI)__instance).SwitchToBehaviourState(2); } ((EnemyAI)__instance).targetPlayer = null; ((EnemyAI)__instance).movingTowardsTargetPlayer = false; __instance.lastKnownHivePosition = ((Component)__instance.hive).transform.position + Vector3.up * 0.5f; if (__instance.searchForHive.inProgress) { ((EnemyAI)__instance).StopSearch(__instance.searchForHive, true); } ((EnemyAI)__instance).agent.acceleration = 16f; ((EnemyAI)__instance).SetDestinationToPosition(__instance.lastKnownHivePosition, false); if (((Behaviour)((EnemyAI)__instance).agent).enabled && ((EnemyAI)__instance).agent.isOnNavMesh) { Vector3 destination = ((EnemyAI)__instance).destination; Traverse val = Traverse.Create((object)__instance).Field("prevDestination"); if (destination != val.GetValue<Vector3>() && ((EnemyAI)__instance).agent.SetDestination(destination)) { val.SetValue((object)destination); } } ((EnemyAI)__instance).SyncPositionToClients(); return false; } private static void StopFollowing(RedLocustBees bees, string reason) { followingDroneHive.Remove(bees); } internal static void Forget(RedLocustBees bees) { followingDroneHive.Remove(bees); } } [HarmonyPatch(typeof(EnemyAI), "OnDestroy")] internal static class CircuitBeeDroneHiveCleanupPatch { [HarmonyPostfix] private static void OnDestroyPostfix(EnemyAI __instance) { RedLocustBees val = (RedLocustBees)(object)((__instance is RedLocustBees) ? __instance : null); if (val != null) { CircuitBeeDroneHivePatch.Forget(val); } } } [HarmonyPatch(typeof(EnemyAICollisionDetect), "OnTriggerStay")] internal static class CircuitBeeDroneCollisionPatch { [HarmonyPostfix] private static void OnTriggerStayPostfix(EnemyAICollisionDetect __instance, Collider other) { EnemyAI mainScript = __instance.mainScript; RedLocustBees val = (RedLocustBees)(object)((mainScript is RedLocustBees) ? mainScript : null); if (val != null && ((NetworkBehaviour)val).IsOwner && !((EnemyAI)val).isEnemyDead && !(((EnemyAI)val).stunNormalizedTimer > 0f) && !((Object)(object)other == (Object)null) && !other.isTrigger) { DroneController componentInParent = ((Component)other).GetComponentInParent<DroneController>(); if ((Object)(object)componentInParent != (Object)null) { componentInParent.ReportCircuitBeeCollision(val); } } } } [HarmonyPatch] internal static class DroneDamagePatches { [HarmonyPatch(typeof(ShotgunItem), "ShootGun")] [HarmonyPostfix] private static void ShotgunShootGunPostfix(ShotgunItem __instance, Vector3 shotgunPosition, Vector3 shotgunForward) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB playerHeldBy = ((GrabbableObject)__instance).playerHeldBy; if ((Object)(object)playerHeldBy == (Object)null || !((NetworkBehaviour)playerHeldBy).IsOwner) { return; } Vector3 val = shotgunForward; if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { return; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return; } val = Vector3.Normalize(val); Ray val2 = default(Ray); ((Ray)(ref val2))..ctor(shotgunPosition - val * 10f, val); RaycastHit[] array = Physics.SphereCastAll(val2, 5f, 15f, 524288, (QueryTriggerInteraction)2); HashSet<ulong> hashSet = new HashSet<ulong>(); RaycastHit[] array2 = array; for (int i = 0; i < array2.Length; i++) { RaycastHit val3 = array2[i]; if (!((Object)(object)((RaycastHit)(ref val3)).collider == (Object)null) && !(((RaycastHit)(ref val3)).distance <= 0f) && !(((RaycastHit)(ref val3)).point == ((Ray)(ref val2)).origin)) { DroneController componentInParent = ((Component)((RaycastHit)(ref val3)).collider).GetComponentInParent<DroneController>(); if (!((Object)(object)componentInParent == (Object)null) && !componentInParent.IsDisabled && componentInParent.HasShotLineOfSight(shotgunPosition, ((RaycastHit)(ref val3)).point, instance.collidersAndRoomMaskAndDefault) && hashSet.Add(((NetworkBehaviour)componentInParent).NetworkObjectId)) { float num = Vector3.Distance(shotgunPosition, ((RaycastHit)(ref val3)).point); int force = ((num < 3.7f) ? 5 : ((num < 6f) ? 3 : 2)); componentInParent.ReportShotgunHit(shotgunPosition, val, force); } } } } [HarmonyPatch(typeof(Landmine), "SpawnExplosion")] [HarmonyPostfix] private static void LandmineSpawnExplosionPostfix(Vector3 explosionPosition, float damageRange, bool goThroughCar) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsServer || (Object)(object)StartOfRound.Instance == (Object)null) { return; } RaycastHit val = default(RaycastHit); foreach (DroneController item in DroneRegistry.All) { if (!((Object)(object)item == (Object)null) && !item.IsDisabled) { float num = Vector3.Distance(explosionPosition, ((Component)item).transform.position); if (!(num >= damageRange) && !(num >= 4.5f) && (!Physics.Linecast(explosionPosition, ((Component)item).transform.position + Vector3.up * 0.3f, ref val, 1073742080, (QueryTriggerInteraction)1) || ((goThroughCar || ((Component)((RaycastHit)(ref val)).collider).gameObject.layer != 30) && !(num > 4f)))) { item.DamageFromExplosion(6); } } } } } [HarmonyPatch(typeof(Terminal))] internal static class DroneShopPatches { private sealed class PendingPurchase { internal readonly List<DroneController> Drones; internal readonly int ExpectedCredits; internal readonly int OrderedCountBefore; internal readonly int OtherItemCount; internal PendingPurchase(List<DroneController> drones, int expectedCredits, int orderedCountBefore, int otherItemCount) { Drones = drones; ExpectedCredits = expectedCredits; OrderedCountBefore = orderedCountBefore; OtherItemCount = otherItemCount; } } private const string DroneShopItemName = "LCDrone"; private const int RejectedPurchaseSentinel = -100; internal static bool HooksInstalled { get; private set; } internal static void SetHooksInstalled(bool installed) { HooksInstalled = installed; } [HarmonyPrefix] [HarmonyPatch("LoadNewNodeIfAffordable")] private static bool LoadNewNodeIfAffordablePrefix(Terminal __instance, TerminalNode node) { if ((Object)(object)node == (Object)null || node.isConfirmationNode || !TryGetDroneShopIndex(__instance, out var index) || node.buyItemIndex != index) { return true; } int num = Math.Max(1, __instance.playerDefinedAmount); if (num > 4 - DroneRegistry.Count) { LoadResult(__instance, $"You can have at most {4} drones at once.\n\n"); return false; } if (!((NetworkBehaviour)__instance).IsServer) { return true; } int purchaseCost = GetPurchaseCost(__instance, index, num); if (purchaseCost == int.MaxValue) { LoadResult(__instance, "The drone shop price is invalid.\n\n"); return false; } return CompletePurchase(__instance, node, num, purchaseCost); } [HarmonyPrefix] [HarmonyPatch("BuyItemsServerRpc")] private static bool BuyItemsServerRpcPrefix(Terminal __instance, ref int[] boughtItems, int newGroupCredits, ref int numItemsInShip, ref PendingPurchase? __state) { if (!((NetworkBehaviour)__instance).IsServer || boughtItems == null || boughtItems.Length == 0 || !TryGetDroneShopIndex(__instance, out var droneIndex)) { return true; } int num = boughtItems.Count((int index) => index == droneIndex); if (num == 0) { return true; } string error = null; int numberOfItemsInDropship = __instance.numberOfItemsInDropship; int num2 = boughtItems.Length - num; if (boughtItems.Length > 12 || numItemsInShip < boughtItems.Length || numItemsInShip > 12 || num > 4 - DroneRegistry.Count || numberOfItemsInDropship < 0 || numberOfItemsInDropship > 12 || numberOfItemsInDropship + num2 > 12 || newGroupCredits < 0 || __instance.groupCredits < 0 || !TryGetMinimumOrderSpend(__instance, boughtItems, out var minimumSpend) || newGroupCredits > __instance.groupCredits - minimumSpend || !TrySpawnPurchasedDrones(num, out List<DroneController> spawned, out error)) { Plugin.Logger.LogWarning((object)("Drone shop purchase was rejected: " + (error ?? "insufficient or invalid credits"))); int num3 = Math.Max(0, Math.Min(12, __instance.numberOfItemsInDropship)); __instance.SyncGroupCreditsClientRpc(__instance.groupCredits, -100 - num3); return false; } int[] array = boughtItems.Where((int index) => index != droneIndex).ToArray(); numItemsInShip = numberOfItemsInDropship + array.Length; if (array.Length == 0) { __instance.groupCredits = newGroupCredits; __instance.SyncGroupCreditsClientRpc(newGroupCredits, numItemsInShip); DroneFleetSave.CommitPurchase(spawned); return false; } boughtItems = array; __state = new PendingPurchase(spawned, newGroupCredits, __instance.orderedItemsFromTerminal.Count, array.Length); return true; } [HarmonyPostfix] [HarmonyPatch("BuyItemsServerRpc")] private static void BuyItemsServerRpcPostfix(Terminal __instance, PendingPurchase? __state) { if (__state == null) { return; } if (__instance.groupCredits == __state.ExpectedCredits && __instance.orderedItemsFromTerminal.Count >= __state.OrderedCountBefore + __state.OtherItemCount) { DroneFleetSave.CommitPurchase(__state.Drones); return; } foreach (DroneController drone in __state.Drones) { drone.DespawnFromServer(); } } [HarmonyFinalizer] [HarmonyPatch("BuyItemsServerRpc")] private static Exception? BuyItemsServerRpcFinalizer(Exception? __exception, PendingPurchase? __state) { if (__exception != null && __state != null) { foreach (DroneController drone in __state.Drones) { drone.DespawnFromServer(); } } return __exception; } [HarmonyPostfix] [HarmonyPatch("SyncGroupCreditsClientRpc")] private static void SyncGroupCreditsClientRpcPostfix(Terminal __instance, int numItemsInShip) { if (numItemsInShip <= -100 && numItemsInShip >= -112) { __instance.numberOfItemsInDropship = -100 - numItemsInShip; LoadResult(__instance, "The purchase was rejected by the host. No credits were spent. Check the drone and 12-item limits, then try again.\n\n"); } } private static bool CompletePurchase(Terminal terminal, TerminalNode receiptNode, int amount, int totalCost) { if (terminal.groupCredits < totalCost) { return true; } if (amount > 4 - DroneRegistry.Count) { LoadResult(terminal, $"You can have at most {4} drones at once.\n\n"); return false; } if (!TrySpawnPurchasedDrones(amount, out List<DroneController> spawned, out string error)) { LoadResult(terminal, "The drone could not be purchased: " + error + "\n\n"); return false; } terminal.groupCredits -= totalCost; terminal.SyncGroupCreditsClientRpc(terminal.groupCredits, terminal.numberOfItemsInDropship); DroneFleetSave.CommitPurchase(spawned); terminal.LoadNewNode(receiptNode); return false; } private static bool TrySpawnPurchasedDrones(int amount, out List<DroneController> spawned, out string? error) { spawned = new List<DroneController>(); if (!DroneFleetSave.Ready) { error = "The saved fleet is still loading or cannot be read. Check the host log."; return false; } for (int i = 0; i < amount; i++) { DroneController droneController = DroneSpawner.SpawnOnShip(out error, null, null, owned: true); if ((Object)(object)droneController == (Object)null) { foreach (DroneController item in spawned) { item.DespawnFromServer(); } return false; } spawned.Add(droneController); } error = null; return true; } private static bool TryGetPriceInputs(Terminal terminal, int itemIndex, out int creditsWorth, out int salePercent) { creditsWorth = 0; salePercent = 0; if (terminal.buyableItemsList == null || itemIndex < 0 || itemIndex >= terminal.buyableItemsList.Length || terminal.itemSalesPercentages == null || itemIndex >= terminal.itemSalesPercentages.Length || (Object)(object)terminal.buyableItemsList[itemIndex] == (Object)null) { return false; } creditsWorth = terminal.buyableItemsList[itemIndex].creditsWorth; salePercent = terminal.itemSalesPercentages[itemIndex]; return true; } private static int GetPurchaseCost(Terminal terminal, int itemIndex, int amount) { if (!TryGetPriceInputs(terminal, itemIndex, out var creditsWorth, out var salePercent)) { return int.MaxValue; } int num = PurchasePricing.BatchCost(creditsWorth, salePercent, amount); if (num >= 0) { return num; } return int.MaxValue; } private static bool TryGetMinimumOrderSpend(Terminal terminal, int[] items, out long minimumSpend) { minimumSpend = 0L; foreach (IGrouping<int, int> item in from index in items group index by index) { if (!TryGetPriceInputs(terminal, item.Key, out var creditsWorth, out var salePercent)) { return false; } long num = PurchasePricing.MinimumSpend(creditsWorth, salePercent, item.Count()); if (num < 0) { return false; } minimumSpend += num; } return true; } private static bool TryGetDroneShopIndex(Terminal terminal, out int index) { index = -1; if (terminal.buyableItemsList == null) { return false; } for (int i = 0; i < terminal.buyableItemsList.Length; i++) { Item val = terminal.buyableItemsList[i]; if ((Object)(object)val != (Object)null && string.Equals(val.itemName, "LCDrone", StringComparison.OrdinalIgnoreCase)) { index = i; return true; } } return false; } private static void LoadResult(Terminal terminal, string text) { TerminalNode val = ScriptableObject.CreateInstance<TerminalNode>(); val.displayText = text; val.clearPreviousText = true; terminal.LoadNewNode(val); } } public sealed class LCDroneShopPurchasePredicate : DuskTerminalPredicate { public override void Register(NamespacedKey namespacedKey) { } public override TerminalPurchaseResult CanPurchase() { if (!DroneShopPatches.HooksInstalled) { return (TerminalPurchaseResult)(object)TerminalPurchaseResult.Hidden(); } return (TerminalPurchaseResult)(object)TerminalPurchaseResult.Success(); } } [HarmonyPatch(typeof(SpringManAI), "Update")] internal static class CoilHeadDroneVisionPatch { private const float VisionRange = 60f; private const float VisionHalfAngle = 35f; private const float StopInterval = 0.3f; private static readonly HashSet<SpringManAI> stoppedForDroneVision = new HashSet<SpringManAI>(); [HarmonyPrefix] private static void UpdatePrefix(SpringManAI __instance) { if (!((NetworkBehaviour)__instance).IsOwner || ((EnemyAI)__instance).isEnemyDead || ((EnemyAI)__instance).currentBehaviourStateIndex != 1) { return; } bool flag = IsVisible(__instance); UpdateVisibilityLog(__instance, flag); if (flag) { Traverse val = Traverse.Create((object)__instance); Traverse<bool> val2 = val.Field<bool>("stoppingMovement"); if (!val2.Value) { __instance.SetAnimationStopServerRpc(); val2.Value = true; } Traverse<float> val3 = val.Field<float>("stopAndGoMinimumInterval"); if (val3.Value < 0.3f) { val3.Value = 0.3f; } } } [HarmonyPostfix] private static void UpdatePostfix(SpringManAI __instance) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) if (((EnemyAI)__instance).isEnemyDead) { Forget(__instance); } else { if (((EnemyAI)__instance).currentBehaviourStateIndex != 0) { return; } bool flag = IsVisible(__instance); if (((NetworkBehaviour)__instance).IsOwner) { UpdateVisibilityLog(__instance, flag); } if (!flag) { return; } if (((NetworkBehaviour)__instance).IsOwner && (Object)(object)((EnemyAI)__instance).agent != (Object)null) { stoppedForDroneVision.Add(__instance); if (((EnemyAI)__instance).agent.isOnOffMeshLink) { Traverse.Create((object)__instance).Method("StopOffMeshLinkMovement", Array.Empty<object>()).GetValue(); } ((EnemyAI)__instance).agent.speed = 0f; if (((Behaviour)((EnemyAI)__instance).agent).enabled && ((EnemyAI)__instance).agent.isOnNavMesh) { ((EnemyAI)__instance).agent.velocity = Vector3.zero; } } if ((Object)(object)((EnemyAI)__instance).creatureAnimator != (Object)null) { ((EnemyAI)__instance).creatureAnimator.SetFloat("walkSpeed", 0f); } } } private static bool IsVisible(SpringManAI coil) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (!DroneVision.IsVisibleFromAnyDrone(((Component)coil).transform.position + Vector3.up * 0.6f, 60f, 35f, DroneVisionTarget.CoilHead)) { return DroneVision.IsVisibleFromAnyDrone(((Component)coil).transform.position + Vector3.up * 3f, 60f, 35f, DroneVisionTarget.CoilHead); } return true; } private static void UpdateVisibilityLog(SpringManAI coil, bool visible) { if (visible) { stoppedForDroneVision.Add(coil); } else { stoppedForDroneVision.Remove(coil); } } internal static void Forget(SpringManAI coil) { stoppedForDroneVision.Remove(coil); } } [HarmonyPatch(typeof(EnemyAI), "OnDestroy")] internal static class CoilHeadDroneVisionCleanupPatch { [HarmonyPostfix] private static void OnDestroyPostfix(EnemyAI __instance) { SpringManAI val = (SpringManAI)(object)((__instance is SpringManAI) ? __instance : null); if (val != null) { CoilHeadDroneVisionPatch.Forget(val); } } } [HarmonyPatch(typeof(FlowermanAI), "Update")] internal static class BrackenDroneVisionPatch { private const float VisionRange = 30f; private const float VisionHalfAngle = 35f; private static readonly HashSet<FlowermanAI> evadingDroneVision = new HashSet<FlowermanAI>(); [HarmonyPrefix] private static void UpdatePrefix(FlowermanAI __instance) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (((NetworkBehaviour)__instance).IsOwner && !((EnemyAI)__instance).isEnemyDead && ((EnemyAI)__instance).currentBehaviourStateIndex == 0) { if (!DroneVision.IsVisibleFromAnyDrone(((Component)__instance).transform.position + Vector3.up * 0.5f, 30f, 35f, DroneVisionTarget.Bracken)) { evadingDroneVision.Remove(__instance); return; } __instance.evadeStealthTimer = 0f; evadingDroneVision.Add(__instance); ((EnemyAI)__instance).SwitchToBehaviourState(1); } } internal static void Forget(FlowermanAI bracken) { evadingDroneVision.Remove(bracken); } } [HarmonyPatch(typeof(EnemyAI), "OnDestroy")] internal static class BrackenDroneVisionCleanupPatch { [HarmonyPostfix] private static void OnDestroyPostfix(EnemyAI __instance) { FlowermanAI val = (FlowermanAI)(object)((__instance is FlowermanAI) ? __instance : null); if (val != null) { BrackenDroneVisionPatch.Forget(val); } } } internal static class EnemyDroneDebugLog { [Conditional("DEBUG")] internal static void Log(EnemyAI enemy, DroneController drone, string message) { } [Conditional("DEBUG")] internal static void Log(EnemyAI enemy, string message) { } } [HarmonyPatch(typeof(PumaAI), "DetectNoise", new Type[] { typeof(Vector3), typeof(float), typeof(int), typeof(int) })] internal static class FeioparDroneNoisePatch { [HarmonyPrefix] private static bool DetectNoisePrefix(PumaAI __instance) { bool result = ((NetworkBehaviour)__instance).IsOwner || !DroneNoise.IsPlaying; _ = DroneNoise.IsPlaying; return result; } } [HarmonyPatch(typeof(PumaAI), "Update")] internal static class FeioparDroneVisionPatch { private const float VisionRange = 30f; private const float VisionHalfAngle = 35f; private static readonly HashSet<PumaAI> startledWhileVisible = new HashSet<PumaAI>(); [HarmonyPostfix] private static void UpdatePostfix(PumaAI __instance) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)__instance).IsSpawned || ((EnemyAI)__instance).isEnemyDead) { Forget(__instance); return; } if (((EnemyAI)__instance).currentBehaviourStateIndex != 1) { startledWhileVisible.Remove(__instance); return; } Vector3 targetPosition = (((Object)(object)((EnemyAI)__instance).eye != (Object)null) ? ((EnemyAI)__instance).eye.position : (((Component)__instance).transform.position + Vector3.up * 1.5f)); if (!DroneVision.TryGetVisibleDronePosition(targetPosition, 30f, 35f, DroneVisionTarget.Feiopar, out var dronePosition)) { startledWhileVisible.Remove(__instance); } else if (startledWhileVisible.Add(__instance) && ((NetworkBehaviour)__instance).IsOwner) { __instance.PingAttention(15, 0.6f, dronePosition + Vector3.up * 0.7f, true, true); } else if (!((NetworkBehaviour)__instance).IsOwner) { startledWhileVisible.Remove(__instance); } } internal static void Forget(PumaAI feiopar) { startledWhileVisible.Remove(feiopar); } } [HarmonyPatch(typeof(EnemyAI), "OnDestroy")] internal static class FeioparDroneVisionCleanupPatch { [HarmonyPostfix] private static void OnDestroyPostfix(EnemyAI __instance) { PumaAI val = (PumaAI)(object)((__instance is PumaAI) ? __instance : null); if (val != null) { FeioparDroneVisionPatch.Forget(val); } } } [HarmonyPatch(typeof(ForestGiantAI), "DoAIInterval")] internal static class ForestGiantDroneAwarenessPatches { private const int DroneNoticeRange = 45; private static readonly HashSet<ForestGiantAI> giantsThatNoticedDrone = new HashSet<ForestGiantAI>(); private static readonly HashSet<ForestGiantAI> giantsLoggedInitialCheck = new HashSet<ForestGiantAI>(); private static readonly HashSet<ForestGiantAI> giantsLoggedNonIdleState = new HashSet<ForestGiantAI>(); private static readonly HashSet<ForestGiantAI> giantsWithVisibleDrone = new HashSet<ForestGiantAI>(); private static readonly HashSet<ForestGiantAI> giantsLoggedExistingInvestigation = new HashSet<ForestGiantAI>(); private static readonly HashSet<ForestGiantAI> giantsLoggedNoVisibleDrone = new HashSet<ForestGiantAI>(); [HarmonyPostfix] private static void DoAIIntervalPostfix(ForestGiantAI __instance) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)__instance).IsOwner || ((EnemyAI)__instance).isEnemyDead) { return; } giantsLoggedInitialCheck.Add(__instance); if (((EnemyAI)__instance).currentBehaviourStateIndex != 0) { giantsLoggedNonIdleState.Add(__instance); giantsWithVisibleDrone.Remove(__instance); giantsThatNoticedDrone.Remove(__instance); giantsLoggedExistingInvestigation.Remove(__instance); return; } giantsLoggedNonIdleState.Remove(__instance); DroneController droneController = null; int num = 0; float num2 = float.PositiveInfinity; foreach (DroneController item in DroneRegistry.All) { if (!((Object)(object)item == (Object)null) && ((Behaviour)item).isActiveAndEnabled && !item.IsDisabled && !item.OnShip && item.ForestGiantInvestigatesDrone) { num++; Vector3 val = ((Component)item).transform.position - ((Component)__instance).transform.position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num2 && ((EnemyAI)__instance).CheckLineOfSightForPosition(((Component)item).transform.position, 45f, 45, -1f, (Transform)null)) { droneController = item; num2 = sqrMagnitude; } } } if ((Object)(object)droneController == (Object)null) { if (!giantsWithVisibleDrone.Remove(__instance)) { giantsLoggedNoVisibleDrone.Add(__instance); } giantsThatNoticedDrone.Remove(__instance); giantsLoggedExistingInvestigation.Remove(__instance); return; } if (giantsWithVisibleDrone.Add(__instance)) { giantsLoggedNoVisibleDrone.Remove(__instance); } if (__instance.investigating) { giantsLoggedExistingInvestigation.Add(__instance); return; } giantsLoggedExistingInvestigation.Remove(__instance); if (giantsThatNoticedDrone.Add(__instance)) { __instance.investigatePosition = RoundManager.Instance.GetNavMeshPosition(((Component)droneController).transform.position, default(NavMeshHit), 5f, ((EnemyAI)__instance).agentMask); __instance.investigating = true; } } internal static void Forget(ForestGiantAI giant) { giantsThatNoticedDrone.Remove(giant); giantsLoggedInitialCheck.Remove(giant); giantsLoggedNonIdleState.Remove(giant); giantsWithVisibleDrone.Remove(giant); giantsLoggedExistingInvestigation.Remove(giant); giantsLoggedNoVisibleDrone.Remove(giant); } } [HarmonyPatch(typeof(EnemyAI), "OnDestroy")] internal static class ForestGiantDroneAwarenessCleanupPatches { [HarmonyPostfix] private static void OnDestroyPostfix(EnemyAI __instance) { ForestGiantAI val = (ForestGiantAI)(object)((__instance is ForestGiantAI) ? __instance : null); if (val != null) { ForestGiantDroneAwarenessPatches.Forget(val); } } } [HarmonyPatch(typeof(GameNetworkManager))] internal static class GameNetworkManagerSavePatches { [HarmonyPrefix] [HarmonyPatch("ResetSavedGameValues")] private static void ResetSavedGameValuesPrefix() { DroneFleetSave.ClearForRunReset(); } [HarmonyPostfix] [HarmonyPatch("SaveGame")] private static void SaveGamePostfix(GameNetworkManager __instance) { DroneFleetSave.FlushOnVanillaSave(__instance); } } [HarmonyPatch(typeof(HoarderBugAI))] internal static class HoarderBugPatches { [HarmonyPostfix] [HarmonyPatch("RefreshGrabbableObjectsInMapList")] private static void RefreshGrabbableObjectsInMapListPostfix() { for (int num = HoarderBugAI.grabbableObjectsInMap.Count - 1; num >= 0; num--) { GameObject val = HoarderBugAI.grabbableObjectsInMap[num]; GrabbableObject val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<GrabbableObject>() : null); if ((Object)(object)val2 == (Object)null || CargoAnchors.IsDroneCargoAnchor(val2.parentObject)) { HoarderBugAI.grabbableObjectsInMap.RemoveAt(num); } } } [HarmonyPrefix] [HarmonyPatch("GrabTargetItemIfClose")] private static bool GrabTargetItemIfClosePrefix(HoarderBugAI __instance, ref bool __result) { GrabbableObject targetItem = __instance.targetItem; if ((Object)(object)targetItem == (Object)null || !CargoAnchors.IsDroneCargoAnchor(targetItem.parentObject)) { return true; } __instance.targetItem = null; __result = false; return false; } [HarmonyPrefix] [HarmonyPatch("GrabItem", new Type[] { typeof(NetworkObject) })] private static bool GrabItemPrefix(HoarderBugAI __instance, NetworkObject item) { GrabbableObject val = (((Object)(object)item != (Object)null) ? ((Component)item).GetComponent<GrabbableObject>() : null); if ((Object)(object)val == (Object)null || !CargoAnchors.IsDroneCargoAnchor(val.parentObject)) { return true; } if (Traverse.Create((object)__instance).Field<bool>("sendingGrabOrDropRPC").Value) { return true; } if ((Object)(object)__instance.targetItem == (Object)(object)val) { __instance.targetItem = null; } if (((NetworkBehaviour)__instance).IsOwner && ((EnemyAI)__instance).currentBehaviourStateIndex == 1 && __instance.heldItem == null) { ((EnemyAI)__instance).SwitchToBehaviourStateOnLocalClient(0); } return false; } [HarmonyPostfix] [HarmonyPatch("GrabItem", new Type[] { typeof(NetworkObject) })] private static void GrabItemPostfix(NetworkObject item) { GrabbableObject val = (((Object)(object)item != (Object)null) ? ((Component)item).GetComponent<GrabbableObject>() : null); if ((Object)(object)val != (Object)null) { val.isHeldByEnemy = true; HoarderBugAI.grabbableObjectsInMap.Remove(((Component)val).gameObject); } } [HarmonyPostfix] [HarmonyPatch("DropItem", new Type[] { typeof(NetworkObject), typeof(Vector3), typeof(bool) })] private static void DropItemPostfix(NetworkObject item) { GrabbableObject val = (((Object)(object)item != (Object)null) ? ((Component)item).GetComponent<GrabbableObject>() : null); if ((Object)(object)val != (Object)null) { val.isHeldByEnemy = false; } } } [HarmonyPatch(typeof(BlobAI), "DoAIInterval")] internal static class HygrodereDronePatches { private const float FollowRange = 4f; private static readonly Dictionary<BlobAI, DroneController> followedDrones = new Dictionary<BlobAI, DroneController>(); [HarmonyPostfix] private static void DoAIIntervalPostfix(BlobAI __instance) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)__instance).IsOwner || ((EnemyAI)__instance).isEnemyDead) { return; } int num; if ((Object)(object)((EnemyAI)__instance).targetPlayer != (Object)null) { Vector3 val = ((Component)((EnemyAI)__instance).targetPlayer).transform.position - ((Component)__instance).transform.position; num = ((((Vector3)(ref val)).sqrMagnitude < 16f) ? 1 : 0); } else { num = 0; } bool flag = (byte)num != 0; if (((EnemyAI)__instance).stunNormalizedTimer > 0f || flag || StartOfRound.Instance.allPlayersDead) { ClearFollowTarget(__instance, "yielding to vanilla player/stun behavior"); return; } DroneController droneController = FindNearestDrone(__instance, 4f); if ((Object)(object)droneController == (Object)null || (Object)(object)RoundManager.Instance == (Object)null) { ClearFollowTarget(__instance, "no eligible drone within follow range"); return; } if (!followedDrones.TryGetValue(__instance, out DroneController value) || (Object)(object)value != (Object)(object)droneController) { followedDrones[__instance] = droneController; } ((EnemyAI)__instance).StopSearch(__instance.searchForPlayers, true); ((EnemyAI)__instance).movingTowardsTargetPlayer = false; Vector3 navMeshPosition = RoundManager.Instance.GetNavMeshPosition(((Component)droneController).transform.position, default(NavMeshHit), 5f, ((EnemyAI)__instance).agentMask); ((EnemyAI)__instance).SetDestinationToPosition(navMeshPosition, false); } private static DroneController? FindNearestDrone(BlobAI blob, float range) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) DroneController result = null; float num = range * range; foreach (DroneController item in DroneRegistry.All) { if (!((Object)(object)item == (Object)null) && ((Behaviour)item).isActiveAndEnabled && !item.IsDisabled && item.IsInside && !item.OnShip && item.HygrodereFollowsDrone) { Vector3 val = ((Component)item).transform.position - ((Component)blob).transform.position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (!(sqrMagnitude >= num)) { result = item; num = sqrMagnitude; } } } return result; } internal static void Forget(BlobAI blob) { ClearFollowTarget(blob, "Hygrodere removed"); foreach (DroneController item in DroneRegistry.All) { if ((Object)(object)item != (Object)null) { item.SetHygrodereSlow(blob, slowed: false); } } } private static void ClearFollowTarget(BlobAI blob, string reason) { if (followedDrones.TryGetValue(blob, out DroneController _)) { followedDrones.Remove(blob); } } } [HarmonyPatch(typeof(BlobAI), "Update")] internal static class HygrodereDroneSlowPatch { private const float SlowRange = 4f; [HarmonyPostfix] private static void UpdatePostfix(BlobAI __instance) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsServer) { return; } foreach (DroneController item in DroneRegistry.All) { int num; if (!((EnemyAI)__instance).isEnemyDead && (Object)(object)item != (Object)null && ((Behaviour)item).isActiveAndEnabled && !item.IsDisabled && item.IsInside && !item.OnShip && item.HygrodereFollowsDrone) { Vector3 val = ((Component)item).transform.position - ((Component)__instance).transform.position; num = ((((Vector3)(ref val)).sqrMagnitude < 16f) ? 1 : 0); } else { num = 0; } bool slowed = (byte)num != 0; if ((Object)(object)item != (Object)null) { item.SetHygrodereSlow(__instance, slowed); } } } } [HarmonyPatch(typeof(EnemyAI), "OnDestroy")] internal static class HygrodereDroneCleanupPatch { [HarmonyPostfix] private static void OnDestroyPostfix(EnemyAI __instance) { BlobAI val = (BlobAI)(object)((__instance is BlobAI) ? __instance : null); if (val != null) { HygrodereDronePatches.Forget(val); } } } [HarmonyPatch(typeof(BushWolfEnemy), "Update")] internal static class KidnapperFoxDroneVisionPatch { private sealed class ReactionState { internal Vector3 DronePosition; internal float LookTimer; internal bool HasReactedWhileVisible; internal bool IsLooking; internal bool PreviousAgentUpdateRotation; internal float PreviousAgentSpeed; internal bool PendingSpeedRestore; } private const float VisionRange = 30f; private const float VisionHalfAngle = 35f; private const float LookDuration = 0.55f; private const float RetreatDistance = 4.6f; private const float RetreatSpeed = 5f; private static readonly FieldRef<BushWolfEnemy, float> matingCallTimerRef = AccessTools.FieldRefAccess<BushWolfEnemy, float>("matingCallTimer"); private static readonly Dictionary<BushWolfEnemy, ReactionState> reactions = new Dictionary<BushWolfEnemy, ReactionState>(); [HarmonyPostfix] private static void UpdatePostfix(BushWolfEnemy __instance) { //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022b: 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_02c9: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)__instance).IsSpawned || ((EnemyAI)__instance).isEnemyDead) { Forget(__instance); return; } StartOfRound instance = StartOfRound.Instance; reactions.TryGetValue(__instance, out ReactionState value); bool flag = ((EnemyAI)__instance).stunNormalizedTimer > 0f; bool flag2 = matingCallTimerRef.Invoke(__instance) >= 0f; if (value != null && value.PendingSpeedRestore && !flag && !flag2 && ((EnemyAI)__instance).currentBehaviourStateIndex == 0 && __instance.isHiding && (Object)(object)((EnemyAI)__instance).agent != (Object)null) { ((EnemyAI)__instance).agent.speed = value.PreviousAgentSpeed; value.PendingSpeedRestore = false; } if (!((NetworkBehaviour)__instance).IsOwner || (Object)(object)instance == (Object)null || instance.livingPlayers == 0 || ((EnemyAI)__instance).currentBehaviourStateIndex != 0 || !__instance.isHiding || flag || (Object)(object)__instance.staringAtPlayer != (Object)null || flag2 || (Object)(object)((EnemyAI)__instance).agent == (Object)null) { if (value != null && value.IsLooking) { RestoreAgentRotation(__instance, value); value.IsLooking = false; if (flag || flag2) { value.PendingSpeedRestore = true; } else if ((Object)(object)((EnemyAI)__instance).agent != (Object)null && ((EnemyAI)__instance).agent.speed <= 0f && (Object)(object)__instance.staringAtPlayer == (Object)null && ((EnemyAI)__instance).currentBehaviourStateIndex != 2) { ((EnemyAI)__instance).agent.speed = value.PreviousAgentSpeed; } } if (value != null && (((EnemyAI)__instance).currentBehaviourStateIndex != 0 || !__instance.isHiding)) { value.PendingSpeedRestore = false; } if (value == null || !value.PendingSpeedRestore) { reactions.Remove(__instance); } return; } NavMeshAgent agent = ((EnemyAI)__instance).agent; Vector3 targetPosition = (((Object)(object)((EnemyAI)__instance).eye != (Object)null) ? ((EnemyAI)__instance).eye.position : (((Component)__instance).transform.position + Vector3.up * 0.75f)); Vector3 dronePosition; bool flag3 = DroneVision.TryGetVisibleDronePosition(targetPosition, 30f, 35f, DroneVisionTarget.KidnapperFox, out dronePosition); if (!flag3) { if (value != null) { value.HasReactedWhileVisible = false; if (!value.IsLooking) { reactions.Remove(__instance); } } } else if (value == null) { value = new ReactionState(); reactions.Add(__instance, value); } if (value == null) { return; } if (flag3) { value.DronePosition = dronePosition; if (!value.HasReactedWhileVisible && !value.IsLooking) { value.IsLooking = true; value.LookTimer = 0.55f; value.PreviousAgentUpdateRotation = agent.updateRotation; value.PreviousAgentSpeed = agent.speed; } value.HasReactedWhileVisible = true; } if (!value.IsLooking) { return; } LookToward(__instance, value.DronePosition); agent.speed = 0f; value.LookTimer -= Time.deltaTime; if (value.LookTimer <= 0f) { value.IsLooking = false; agent.updateRotation = value.PreviousAgentUpdateRotation; if (!RetreatFromDrone(__instance, value.DronePosition)) { agent.speed = value.PreviousAgentSpeed; } } } private static void RestoreAgentRotation(BushWolfEnemy fox, ReactionState state) { NavMeshAgent agent = ((EnemyAI)fox).agent; if (state.IsLooking && (Object)(object)agent != (Object)null) { agent.updateRotation = state.PreviousAgentUpdateRotation; } } private static void LookToward(BushWolfEnemy fox, Vector3 dronePosition) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) NavMeshAgent agent = ((EnemyAI)fox).agent; if (!((Object)(object)agent == (Object)null)) { Vector3 val = dronePosition; val.y = ((Component)fox).transform.position.y; Vector3 val2 = val - ((Component)fox).transform.position; val2.y = 0f; if (!(((Vector3)(ref val2)).sqrMagnitude <= 0.001f)) { agent.updateRotation = false; ((Component)fox).transform.rotation = Quaternion.Lerp(((Component)fox).transform.rotation, Quaternion.LookRotation(val2, Vector3.up), 4f * Time.deltaTime); } } } private static bool RetreatFromDrone(BushWolfEnemy fox, Vector3 dronePosition) { //IL_0036: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) NavMeshAgent agent = ((EnemyAI)fox).agent; RoundManager instance = RoundManager.Instance; StartOfRound instance2 = StartOfRound.Instance; if ((Object)(object)agent == (Object)null || (Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null) { return false; } Vector3 val = ((Component)fox).transform.position - dronePosition; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude <= 0.001f) { val = ((Component)fox).transform.forward; val.y = 0f; } if (((Vector3)(ref val)).sqrMagnitude <= 0.001f) { return false; } Ray val2 = default(Ray); ((Ray)(ref val2))..ctor(((Component)fox).transform.position + Vector3.up * 0.5f, ((Vector3)(ref val)).normalized); float num = 4.6f; RaycastHit val3 = default(RaycastHit); if (Physics.Raycast(val2, ref val3, 4.6f, instance2.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1)) { num = Mathf.Clamp(((RaycastHit)(ref val3)).distance - 1f, 0f, ((RaycastHit)(ref val3)).distance); } Vector3 navMeshPosition = instance.GetNavMeshPosition(((Ray)(ref val2)).GetPoint(num), default(NavMeshHit), 5f, -1); if (!instance.GotNavMeshPositionResult) { return false; } if (Vector3.Distance(navMeshPosition, ((Component)fox).transform.position) < 0.5f) { return false; } ((EnemyAI)fox).SetDestinationToPosition(navMeshPosition, false); agent.speed = 5f * fox.speedMultiplier; return true; } internal static void Forget(BushWolfEnemy fox) { reactions.Remove(fox); } } [HarmonyPatch(typeof(EnemyAI), "OnDestroy")] internal static class KidnapperFoxDroneVisionCleanupPatch { [HarmonyPostfix] private static void OnDestroyPostfix(EnemyAI __instance) { BushWolfEnemy val = (BushWolfEnemy)(object)((__instance is BushWolfEnemy) ? __instance : null); if (val != null) { KidnapperFoxDroneVisionPatch.Forget(val); } } } [HarmonyPatch(typeof(DoublewingAI), "DoAIInterval")] internal static class ManticoilDronePatches { [HarmonyPostfix] private static void DoAIIntervalPostfix(DoublewingAI __instance) { //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)__instance).IsOwner || ((EnemyAI)__instance).isEnemyDead || ((EnemyAI)__instance).daytimeEnemyLeaving || StartOfRound.Instance.allPlayersDead || ((EnemyAI)__instance).stunNormalizedTimer > 0f) { return; } bool value = Traverse.Create((object)__instance).Field<bool>("oddInterval").Value; if (((EnemyAI)__instance).currentBehaviourStateIndex == 0 && value && !Traverse.Create((object)__instance).Field<bool>("alertingBird").Value) { DroneController droneController = FindVisibleDrone(__instance, 8, 4f); if ((Object)(object)droneController != (Object)null) { Traverse.Create((object)__instance).Field<bool>("alertingBird").Value = true; __instance.AlertBirdServerRpc(); } } else { if (((EnemyAI)__instance).currentBehaviourStateIndex != 1 || Traverse.Create((object)__instance).Field<float>("avoidingPlayer").Value > 0f) { return; } DroneController droneController2 = FindVisibleDrone(__instance, 10, 8f); if (!((Object)(object)droneController2 == (Object)null)) { Transform val = ((EnemyAI)__instance).ChooseFarthestNodeFromPosition(((Component)droneController2).transform.position, false, Random.Range(0, ((EnemyAI)__instance).allAINodes.Length / 2), false, 50, -1); if ((Object)(object)val != (Object)null && ((EnemyAI)__instance).SetDestinationToPosition(val.position, false)) { Traverse.Create((object)__instance).Field<float>("avoidingPlayer").Value = Random.Range(10f, 20f); ((EnemyAI)__instance).StopSearch(__instance.roamGlide, true); } } } } private static DroneController? FindVisibleDrone(DoublewingAI bird, int range, float proximityAwareness) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) DroneController result = null; float num = float.MaxValue; foreach (DroneController item in DroneRegistry.All) { if (!((Object)(object)item == (Object)null) && ((Behaviour)item).isActiveAndEnabled && !item.IsDisabled && !item.IsInside && !item.OnShip && item.ManticoilEvadesFromDrone) { Vector3 val = ((Component)item).transform.position + Vector3.up * 0.3f; float num2 = Vector3.Distance(((EnemyAI)bird).eye.position, val); if (!(num2 >= (float)range) && ((EnemyAI)bird).CheckLineOfSightForPosition(val, 80f, range, proximityAwareness, (Transform)null) && !(num2 >= num)) { result = item; num = num2; } } } return result; } } [HarmonyPatch(typeof(ManualCameraRenderer))] internal static class ManualCameraRendererPatches { private static bool loggedError; private static bool loggedFloorError; internal static void RefreshMapCameraFloor() { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) try { StartOfRound instance = StartOfRound.Instance; ManualCameraRenderer val = (((Object)(object)instance != (Object)null) ? instance.mapScreen : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val.mapCamera == (Object)null) && val.radarTargets != null && val.targetTransformIndex >= 0 && val.targetTransformIndex < val.radarTargets.Count) { Transform val2 = val.radarTargets[val.targetTransformIndex]?.transform; if ((Object)(object)val2 != (Object)null) { AccessTools.Method(typeof(ManualCameraRenderer), "MapCameraFocusOnPosition", (Type[])null, (Type[])null)?.Invoke(val, new object[1] { val2.position }); } } } catch (Exception arg) { if (!loggedFloorError) { loggedFloorError = true; Plugin.Logger.LogError((object)$"Failed to refresh the monitor map floor (logged once): {arg}"); } } } [HarmonyPostfix] [HarmonyPatch("MapCameraFocusOnPosition")] private static void MapCameraFocusOnPositionPostfix(ManualCameraRenderer __instance, Vector3 pos) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) try { if (!((Object)(object)__instance.mapCamera == (Object)null) && MapLabels.TryGetMonitorCameraYOffset(pos, out var offset)) { Transform transform = ((Component)__instance.mapCamera).transform; transform.position += Vector3.up * offset; } } catch (Exception arg) { if (!loggedFloorError) { loggedFloorError = true; Plugin.Logger.LogError((object)$"Failed to switch the monitor map floor (logged once): {arg}"); } } } [HarmonyPostfix] [HarmonyPatch("LateUpdate")] private static void LateUpdatePostfix(ManualCameraRenderer __instance) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) try { if (!__instance.enableHeadMountedCam || (Object)(object)__instance.headMountedCam == (Object)null || (Object)(object)__instance.targetedPlayer != (Object)null) { return; } List<TransformAndName> radarTargets = __instance.radarTargets; int targetTransformIndex = __instance.targetTransformIndex; if (radarTargets != null && targetTransformIndex >= 0 && targetTransformIndex < radarTargets.Count) { Transform val = radarTargets[targetTransformIndex]?.transform; DroneController droneController = default(DroneController); if (!((Object)(object)val == (Object)null) && ((Component)val).TryGetComponent<DroneController>(ref droneController)) { Transform transform = ((Component)__instance.headMountedCam).transform; DroneVision.GetCameraPose(val, out var position, out var rotation); transform.position = position; transform.rotation = rotation; } } } catch (Exception arg) { if (!loggedError) { loggedError = true; Plugin.Logger.LogError((object)$"Failed to place the monitor camera on the drone (logged once): {arg}"); } } } } [HarmonyPatch(typeof(EnemyAICollisionDetect), "OnTriggerStay")] internal static class MouthDogDroneCollisionPatch { private const float ReportInterval = 0.3f; private static readonly Dictionary<(MouthDogAI Dog, DroneController Drone), float> lastReports = new Dictionary<(MouthDogAI, DroneController), float>(); [HarmonyPostfix] private static void OnTriggerStayPostfix(EnemyAICollisionDetect __instance, Collider other) { EnemyAI mainScript = __instance.mainScript; MouthDogAI val = (MouthDogAI)(object)((mainScript is MouthDogAI) ? mainScript : null); if (val == null || !((NetworkBehaviour)val).IsOwner || ((EnemyAI)val).isEnemyDead || ((EnemyAI)val).currentBehaviourStateIndex != 3 || (Object)(object)other == (Object)null) { return; } DroneController componentInParent = ((Component)other).GetComponentInParent<DroneController>(); if (!((Object)(object)componentInParent == (Object)null) && ((Behaviour)componentInParent).isActiveAndEnabled && !componentInParent.IsDisabled && !componentInParent.OnShip && componentInParent.MouthDogAttacksDrone) { float realtimeSinceStartup = Time.realtimeSinceStartup; (MouthDogAI, DroneController) key = (val, componentInParent); if (!lastReports.TryGetValue(key, out var value) || !(realtimeSinceStartup - value < 0.3f)) { lastReports[key] = realtimeSinceStartup; componentInParent.ReportMouthDogCollision(val); } } } internal static void Forget(MouthDogAI dog) { foreach (var item in new List<(MouthDogAI, DroneController)>(lastReports.Keys)) { if ((Object)(object)item.Item1 == (Object)(object)dog) { lastReports.Remove(item); } } } } [HarmonyPatch(typeof(MouthDogAI), "DetectNoise", new Type[] { typeof(Vector3), typeof(float), typeof(int), typeof(int) })] internal static class MouthDogDroneNoisePatch { [HarmonyPrefix] private static bool DetectNoisePrefix(MouthDogAI __instance) { bool result = ((NetworkBehaviour)__instance).IsOwner || !DroneNoise.IsPlaying; _ = DroneNoise.IsPlaying; return result; } } [HarmonyPatch(typeof(EnemyAI), "OnDestroy")] internal static class MouthDogDroneCollisionCleanupPatch { [HarmonyPostfix] private static void OnDestroyPostfix(EnemyAI __instance) { MouthDogAI val = (MouthDogAI)(object)((__instance is MouthDogAI) ? __instance : null); if (val != null) { MouthDogDroneCollisionPatch.Forget(val); } } } [HarmonyPatch(typeof(NutcrackerEnemyAI), "Update")] internal static class NutcrackerDronePatches { private struct MotionSample { internal Vector3 Position; internal float SampledAt; internal float MovingUntil; } private const float SightRange = 60f; private const float SightHalfAngle = 70f; private const float RepeatShotCooldown = 6f; private const float TargetTimeout = 6f; private static readonly Dictionary<NutcrackerEnemyAI, DroneController> droneTargets = new Dictionary<NutcrackerEnemyAI, DroneController>(); private static readonly Dictionary<NutcrackerEnemyAI, float> targetStartTimes = new Dictionary<NutcrackerEnemyAI, float>(); private static readonly Dictionary<NutcrackerEnemyAI, float> lastShotEndTimes = new Dictionary<NutcrackerEnemyAI, float>(); private static readonly Dictionary<NutcrackerEnemyAI, float> lastSightReportTimes = new Dictionary<NutcrackerEnemyAI, float>(); private static readonly HashSet<NutcrackerEnemyAI> aimRequestsStarted = new HashSet<NutcrackerEnemyAI>(); private static readonly HashSet<NutcrackerEnemyAI> resumeInspectionAfterShot = new HashSet<NutcrackerEnemyAI>(); private static readonly Dictionary<DroneController, MotionSample> motionSamples = new Dictionary<DroneController, MotionSample>(); private static readonly List<DroneController> removedMotionSamples = new List<DroneController>(); [HarmonyPostfix] private static void UpdatePostfix(NutcrackerEnemyAI __instance) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) if (!((NetworkBehaviour)__instance).IsSpawned || ((EnemyAI)__instance).isEnemyDead) { Forget(__instance); return; } UpdateDroneMotion(); if (droneTargets.TryGetValue(__instance, out DroneController value)) { float value2; float num = (targetStartTimes.TryGetValue(__instance, out value2) ? value2 : Time.realtimeSinceStartup); bool value3 = Traverse.Create((object)__instance).Field<bool>("aimingGun").Value; if (!IsEligible(value) || Time.realtimeSinceStartup - num > 6f) { CancelTarget(__instance, value); return; } if (((EnemyAI)__instance).currentBehaviourStateIndex != 1 && !value3) { CancelTarget(__instance, value); return; } Traverse.Create((object)__instance).Method("SetTargetDegreesToPosition", new object[1] { ((Component)value).transform.position }).GetValue(); float value4 = Traverse.Create((object)__instance).Field<float>("timeSinceFiringGun").Value; float value5 = Traverse.Create((object)__instance).Field<float>("timeSinceHittingPlayer").Value; if (((NetworkBehaviour)__instance).IsOwner && !aimRequestsStarted.Contains(__instance) && ((EnemyAI)__instance).currentBehaviourStateIndex == 1 && ((EnemyAI)__instance).stunNormalizedTimer <= 0f && !Traverse.Create((object)__instance).Field<bool>("reloadingGun").Value && !value3 && (Object)(object)__instance.gun != (Object)null && __instance.gun.shellsLoaded > 0 && value4 > 0.75f && value5 > 1f && Vector3.Angle(__instance.gun.shotgunRayPoint.forward, ((Component)value).transform.position + Vector3.up * 0.4f - __instance.gun.shotgunRayPoint.position) < 30f) { aimRequestsStarted.Add(__instance); Traverse.Create((object)__instance).Field<float>("timeSinceFiringGun").Value = 0f; ((EnemyAI)__instance).agent.speed = 0f; __instance.AimGunServerRpc(((Component)__instance).transform.position); } } else if (resumeInspectionAfterShot.Contains(__instance) && ((EnemyAI)__instance).currentBehaviourStateIndex == 1 && !Traverse.Create((object)__instance).Field<bool>("aimingGun").Value && !Traverse.Create((object)__instance).Field<bool>("isInspecting").Value) { resumeInspectionAfterShot.Remove(__instance); Traverse.Create((object)__instance).Method("StartInspectionTurn", Array.Empty<object>()).GetValue(); } else { if (!((NetworkBehaviour)__instance).IsOwner || ((EnemyAI)__instance).currentBehaviourStateIndex != 1 || ((EnemyAI)__instance).stunNormalizedTimer > 0f || !Traverse.Create((object)__instance).Field<bool>("isInspecting").Value || (Object)(object)__instance.gun == (Object)null || __instance.gun.shellsLoaded <= 0) { return; } DroneController droneController = FindNearestVisibleMovingDrone(__instance); if (!((Object)(object)droneController == (Object)null)) { float realtimeSinceStartup = Time.realtimeSinceStartup; if (!lastSightReportTimes.TryGetValue(__instance, out var value6) || !(realtimeSinceStartup - value6 < 2f)) { lastSightReportTimes[__instance] = realtimeSinceStartup; droneController.ReportNutcrackerSight(__instance); } } } } internal static bool TryRegisterServerTarget(NutcrackerEnemyAI nutcracker, DroneController drone) { if (droneTargets.ContainsKey(nutcracker) || (lastShotEndTimes.TryGetValue(nutcracker, out var value) && Time.realtimeSinceStartup - value < 6f)) { return false; } droneTargets[nutcracker] = drone; targetStartTimes[nutcracker] = Time.realtimeSinceStartup; aimRequestsStarted.Remove(nutcracker); return true; } internal static bool CanServerSeeDrone(NutcrackerEnemyAI nutcracker, DroneController drone) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)((EnemyAI)nutcracker).eye == (Object)null || !IsEligible(drone) || !motionSamples.TryGetValue(drone, out var value) || value.MovingUntil < Time.realtimeSinceStartup) { return false; } Vector3 val = ((Component)drone).transform.position + Vector3.up * 0.4f; Vector3 val2 = val - ((EnemyAI)nutcracker).eye.position; if (((Vector3)(ref val2)).sqrMagnitude < 3600f && Vector3.Angle(((EnemyAI)nutcracker).eye.forward, val2) < 70f) { return HasClearLineOfSight(nutcracker, drone, val, instance.collidersAndRoomMaskAndDefault); } return false; } internal static DroneController? GetTargetForShot(NutcrackerEnemyAI nutcracker) { if (!droneTargets.TryGetValue(nutcracker, out DroneController value)) { return null; } return value; }