using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Numerics; 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 Dissonance; using Eavesdropper.Art; using Eavesdropper.Core; using GameNetcodeStuff; using HarmonyLib; using LethalLib.Modules; using Microsoft.CodeAnalysis; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [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("Eavesdropper")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.6.2.0")] [assembly: AssemblyInformationalVersion("0.6.2")] [assembly: AssemblyProduct("Eavesdropper")] [assembly: AssemblyTitle("Eavesdropper")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.6.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] 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 Eavesdropper { internal sealed class AdvancedVisual { private sealed class Take { internal float Fps; internal Vector3[][] Positions; internal Quaternion[][] Rotations; } internal Mesh Mesh; internal Material[] Materials = Array.Empty(); private readonly Dictionary takes = new Dictionary(); private static string ReadName(BinaryReader r) { int num = r.ReadInt32(); if (num < 0 || num > 256) { throw new InvalidDataException("Invalid asset name"); } return Encoding.UTF8.GetString(r.ReadBytes(num)); } private static int Count(BinaryReader r, int max) { int num = r.ReadInt32(); if (num < 0 || num > max) { throw new InvalidDataException("Invalid asset count"); } return num; } private static float Float(BinaryReader r) { float num = r.ReadSingle(); if (!float.IsFinite(num)) { throw new InvalidDataException("Nonfinite visual data"); } return num; } internal static AdvancedVisual? Load() { string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)Plugin.Instance).Info.Location), "eavesdropper-visual"); if (!File.Exists(Path.Combine(text, "eavesdropper.mesh"))) { return null; } AdvancedVisual advancedVisual = new AdvancedVisual(); try { advancedVisual.Read(text); Plugin.Instance.Log("Loaded Blender visual and " + advancedVisual.takes.Count + " animation takes."); return advancedVisual; } catch (Exception ex) { Plugin.Instance.Error("Blender visual rejected; using built-in fallback. " + ex.Message); return null; } } private void Read(string folder) { //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Expected O, but got Unknown //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03b5: Unknown result type (might be due to invalid IL or missing references) //IL_03ba: Unknown result type (might be due to invalid IL or missing references) //IL_018f: 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_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_049d: Unknown result type (might be due to invalid IL or missing references) //IL_04a2: Unknown result type (might be due to invalid IL or missing references) //IL_04c2: Expected O, but got Unknown //IL_04f9: Unknown result type (might be due to invalid IL or missing references) //IL_04e3: Unknown result type (might be due to invalid IL or missing references) //IL_0538: Unknown result type (might be due to invalid IL or missing references) //IL_0522: Unknown result type (might be due to invalid IL or missing references) Creature model = CreatureRig.Model; List list = new List(); List list2 = new List(); List list3 = new List(); List list4 = new List(); List[] array = new List[5]; for (int i = 0; i < 5; i++) { array[i] = new List(); } int[] array2; using (BinaryReader binaryReader = new BinaryReader(File.OpenRead(Path.Combine(folder, "eavesdropper.mesh")))) { if (Encoding.ASCII.GetString(binaryReader.ReadBytes(8)) != "EAVMESH1") { throw new InvalidDataException("Mesh version"); } int num = Count(binaryReader, 100); if (num != model.Joints.Count) { throw new InvalidDataException("Rig size"); } array2 = new int[num]; HashSet hashSet = new HashSet(); for (int j = 0; j < num; j++) { array2[j] = model.Bone(ReadName(binaryReader)); if (array2[j] < 0 || !hashSet.Add(array2[j])) { throw new InvalidDataException("Rig names"); } } int num2 = Count(binaryReader, 300); for (int k = 0; k < num2; k++) { ReadName(binaryReader); int num3 = Count(binaryReader, 4); int num4 = Count(binaryReader, 300000); int num5 = Count(binaryReader, 900000); int count = list.Count; if (count + num4 > 400000 || num5 % 3 != 0) { throw new InvalidDataException("Mesh budget"); } for (int l = 0; l < num4; l++) { list.Add(new Vector3(Float(binaryReader), Float(binaryReader), Float(binaryReader))); list2.Add(new Vector3(Float(binaryReader), Float(binaryReader), Float(binaryReader))); list3.Add(new Vector2(Float(binaryReader), Float(binaryReader))); int[] array3 = new int[4]; float[] array4 = new float[4]; float num6 = 0f; for (int m = 0; m < 4; m++) { int num7 = Count(binaryReader, num - 1); array3[m] = array2[num7]; array4[m] = Float(binaryReader); if (array4[m] < 0f) { throw new InvalidDataException("Weight"); } num6 += array4[m]; } if (Math.Abs(num6 - 1f) > 0.01f) { throw new InvalidDataException("Weight sum"); } BoneWeight item = default(BoneWeight); ((BoneWeight)(ref item)).boneIndex0 = array3[0]; ((BoneWeight)(ref item)).boneIndex1 = array3[1]; ((BoneWeight)(ref item)).boneIndex2 = array3[2]; ((BoneWeight)(ref item)).boneIndex3 = array3[3]; ((BoneWeight)(ref item)).weight0 = array4[0]; ((BoneWeight)(ref item)).weight1 = array4[1]; ((BoneWeight)(ref item)).weight2 = array4[2]; ((BoneWeight)(ref item)).weight3 = array4[3]; list4.Add(item); } for (int n = 0; n < num5; n++) { array[num3].Add(count + Count(binaryReader, num4 - 1)); } } } Mesh = new Mesh { name = "Blender armored Eavesdropper", indexFormat = (IndexFormat)1 }; Mesh.SetVertices(list); Mesh.SetNormals(list2); Mesh.SetUVs(0, list3); Mesh.boneWeights = list4.ToArray(); Matrix4x4[] array5 = (Matrix4x4[])(object)new Matrix4x4[array2.Length]; for (int num8 = 0; num8 < array5.Length; num8++) { Vector3 position = model.Joints[num8].Position; array5[num8] = Matrix4x4.Translate(new Vector3(0f - position.X, 0f - position.Y, 0f - position.Z)); } Mesh.bindposes = array5; Mesh.subMeshCount = 5; for (int num9 = 0; num9 < 5; num9++) { Mesh.SetTriangles(array[num9], num9); } Mesh.RecalculateBounds(); Mesh.RecalculateTangents(); Shader val = Shader.Find("HDRP/Lit") ?? Shader.Find("Standard"); if ((Object)(object)val == (Object)null) { throw new InvalidDataException("Missing lit shader"); } string[] names = new string[5] { "Armor", "Sinew", "EarMembrane", "Ivory", "Mouth" }; Materials = (Material[])(object)new Material[5]; int num10; for (num10 = 0; num10 < 5; num10++) { Material val2 = new Material(val) { name = "Eavesdropper " + names[num10] }; Materials[num10] = val2; val2.SetColor("_BaseColor", (Color)((num10 == 4) ? new Color(0.012f, 0.006f, 0.007f) : Color.white)); if (val2.HasProperty("_Color")) { val2.SetColor("_Color", (Color)((num10 == 4) ? new Color(0.012f, 0.006f, 0.007f) : Color.white)); } val2.SetFloat("_Smoothness", (num10 == 0) ? 0.22f : 0.4f); val2.SetFloat("_DoubleSidedEnable", 1f); val2.SetFloat("_CullMode", 0f); val2.SetFloat("_CullModeForward", 0f); val2.EnableKeyword("_DOUBLESIDED_ON"); if (num10 != 4) { Texture2D val3 = LoadTexture("_BaseColor", linear: false); val2.SetTexture("_BaseColorMap", (Texture)(object)val3); if (val2.HasProperty("_MainTex")) { val2.SetTexture("_MainTex", (Texture)(object)val3); } Texture2D val4 = LoadTexture("_Normal", linear: true); val2.SetTexture("_NormalMap", (Texture)(object)val4); if (val2.HasProperty("_BumpMap")) { val2.SetTexture("_BumpMap", (Texture)(object)val4); } val2.EnableKeyword("_NORMALMAP"); val2.EnableKeyword("_NORMALMAP_TANGENT_SPACE"); val2.SetFloat("_NormalScale", 0.45f); Texture2D val5 = LoadTexture("_Mask", linear: true); val2.SetTexture("_MaskMap", (Texture)(object)val5); val2.EnableKeyword("_MASKMAP"); val2.SetFloat("_SmoothnessRemapMin", 0f); val2.SetFloat("_SmoothnessRemapMax", 1f); } } using (BinaryReader binaryReader2 = new BinaryReader(File.OpenRead(Path.Combine(folder, "eavesdropper.anim")))) { if (Encoding.ASCII.GetString(binaryReader2.ReadBytes(8)) != "EAVANIM1" || Count(binaryReader2, 100) != array2.Length) { throw new InvalidDataException("Animation rig/version"); } int num11 = Count(binaryReader2, 64); for (int num12 = 0; num12 < num11; num12++) { string key = ReadName(binaryReader2); int num13 = Count(binaryReader2, 1000); float num14 = Float(binaryReader2); if (num13 < 2 || num14 < 1f || num14 > 120f) { throw new InvalidDataException("Animation rate"); } Take take = new Take { Fps = num14, Positions = new Vector3[num13][], Rotations = new Quaternion[num13][] }; for (int num15 = 0; num15 < num13; num15++) { take.Positions[num15] = new Vector3[array2.Length]; take.Rotations[num15] = new Quaternion[array2.Length]; for (int num16 = 0; num16 < array2.Length; num16++) { take.Positions[num15][array2[num16]] = new Vector3(Float(binaryReader2), Float(binaryReader2), Float(binaryReader2)); Quaternion value = new Quaternion(Float(binaryReader2), Float(binaryReader2), Float(binaryReader2), Float(binaryReader2)); if (value.LengthSquared() < 0.5f) { throw new InvalidDataException("Invalid joint rotation"); } take.Rotations[num15][array2[num16]] = Quaternion.Normalize(value); } } takes.Add(key, take); } } if (!takes.ContainsKey("DoorBash")) { throw new InvalidDataException("Missing DoorBash clip"); } string[] clips = Creature.Clips; foreach (string text in clips) { if (!takes.ContainsKey(text)) { throw new InvalidDataException("Missing clip " + text); } } Texture2D LoadTexture(string suffix, bool linear) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_0059: Expected O, but got Unknown //IL_0067: Expected O, but got Unknown Texture2D val6 = new Texture2D(2, 2, (TextureFormat)4, true, linear) { name = names[num10] + suffix, wrapMode = (TextureWrapMode)0 }; if (!ImageConversion.LoadImage(val6, File.ReadAllBytes(Path.Combine(folder, names[num10] + suffix + ".png")), true)) { throw new InvalidDataException("Invalid texture"); } return val6; } } internal void Sample(string clip, float time, Vector3[] p, Quaternion[] q) { Take take = takes[clip]; float num = (float)(take.Positions.Length - 1) / take.Fps; bool flag; switch (clip) { case "Listen": case "Sprint": case "Wander": case "Dormant": case "Retreat": case "Stunned": case "Investigate": case "DoorCrawl": flag = true; break; default: flag = false; break; } float num2 = (flag ? Mathf.Repeat(Mathf.Max(0f, time), num) : Mathf.Clamp(time, 0f, num)) * take.Fps; int num3 = Mathf.Min((int)num2, take.Positions.Length - 1); int num4 = Mathf.Min(num3 + 1, take.Positions.Length - 1); float amount = num2 - (float)num3; for (int i = 0; i < p.Length; i++) { p[i] = Vector3.Lerp(take.Positions[num3][i], take.Positions[num4][i], amount); q[i] = Quaternion.Slerp(take.Rotations[num3][i], take.Rotations[num4][i], amount); } } } internal static class ConfigMenu { private static bool pending; private static bool oldLook; private static bool oldMove; private static bool oldSpecial; private static bool oldCursor; private static CursorLockMode oldLock; private static PlayerControllerB? player; private static Vector2 scroll; private static string search = ""; private static string message = ""; private static readonly Dictionary drafts = new Dictionary(); internal static bool Open { get; private set; } private static bool Authority { get { if (!((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.IsListening) { return NetworkManager.Singleton.IsServer; } return true; } } private static bool Editable(ConfigEntryBase e) { if (!Authority) { return e.Definition.Section == "Accessibility"; } return true; } private static string Text(object o) { return Convert.ToString(o, CultureInfo.InvariantCulture) ?? ""; } private static void Load() { drafts.Clear(); foreach (KeyValuePair item in from p in (IEnumerable>)((BaseUnityPlugin)Plugin.Instance).Config orderby p.Key.Section, p.Key.Key select p) { drafts[item.Value] = Text(item.Value.BoxedValue); } } internal static void Close() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) if (Open) { Open = false; if ((Object)(object)player != (Object)null) { player.disableLookInput = oldLook; player.disableMoveInput = oldMove; player.inSpecialMenu = oldSpecial; } Cursor.visible = oldCursor; Cursor.lockState = oldLock; player = null; } } internal static void Tick() { //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) if (pending && !EavesdropperAI.Live.Any((EavesdropperAI e) => e.DisplayState == Mode.Attacking || e.DisplayState == Mode.Echolocating)) { Configuration.BindAll(((BaseUnityPlugin)Plugin.Instance).Config, Plugin.Settings); foreach (EavesdropperAI item in EavesdropperAI.Live) { if ((Object)(object)((EnemyAI)item).creatureSFX != (Object)null) { ((EnemyAI)item).creatureSFX.maxDistance = Mathf.Max(35f, Plugin.Settings.EchoRange + 4f); } if ((Object)(object)((EnemyAI)item).creatureVoice != (Object)null) { ((EnemyAI)item).creatureVoice.maxDistance = Mathf.Max(35f, Plugin.Settings.EchoRange + 4f); } } pending = false; message = "Saved and applied. Spawn rarity requires a game restart; initial agitation affects new enemies."; } if (Open && (Object)(object)player != (Object)null && (player.isPlayerDead || (Object)(object)GameNetworkManager.Instance?.localPlayerController != (Object)(object)player)) { Close(); } if (Open && (Object)(object)player == (Object)null) { Keyboard current2 = Keyboard.current; if (current2 != null && ((ButtonControl)current2.escapeKey).wasPressedThisFrame) { Close(); return; } } Keyboard current3 = Keyboard.current; if (current3 == null || !((ButtonControl)current3.f6Key).wasPressedThisFrame) { return; } if (Open) { Close(); return; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if (!((Object)(object)val != (Object)null) || (!val.isPlayerDead && !val.isTypingChat && !val.inTerminalMenu && !val.inSpecialMenu && (!((Object)(object)val.quickMenuManager != (Object)null) || !val.quickMenuManager.isMenuOpen))) { player = val; if ((Object)(object)val != (Object)null) { oldLook = val.disableLookInput; oldMove = val.disableMoveInput; oldSpecial = val.inSpecialMenu; } oldCursor = Cursor.visible; oldLock = Cursor.lockState; Load(); search = ""; scroll = Vector2.zero; Open = true; message = "Edit values, then Save & apply. Closing discards unsaved edits. The game continues while this screen is open."; HoldInput(); } } internal static void HoldInput() { if (Open) { if ((Object)(object)player != (Object)null) { player.disableLookInput = true; player.disableMoveInput = true; player.inSpecialMenu = true; } Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; } } private static void Save() { Dictionary parsed = new Dictionary(); foreach (KeyValuePair draft in drafts) { if (Editable(draft.Key)) { if (!ConfigInput.Parse(draft.Value, draft.Key.SettingType, out object value) || (draft.Key.Description.AcceptableValues != null && !draft.Key.Description.AcceptableValues.IsValid(value))) { message = "Invalid value: " + draft.Key.Definition.Key + ". Use the displayed range and a decimal point."; return; } parsed[draft.Key] = value; } } if (Authority && !ConfigInput.Tiers(Value("AgitationInitial"), Value("AgitationIrritatedThreshold"), Value("AgitationAngryThreshold"), Value("AgitationEnragedThreshold"), Value("AgitationMaximum"))) { message = "Require 0 < Irritated < Angry < Enraged < Maximum, and Initial between zero and Maximum."; return; } ConfigFile config = ((BaseUnityPlugin)Plugin.Instance).Config; bool saveOnConfigSet = config.SaveOnConfigSet; Dictionary dictionary = parsed.ToDictionary, ConfigEntryBase, object>((KeyValuePair p) => p.Key, (KeyValuePair p) => p.Key.BoxedValue); try { config.SaveOnConfigSet = false; foreach (KeyValuePair item in parsed) { if (!object.Equals(item.Key.BoxedValue, item.Value)) { item.Key.BoxedValue = item.Value; } } config.Save(); pending = Authority; message = (pending ? "Saved. Gameplay changes apply when active scans and attacks finish." : "Local accessibility settings saved."); Load(); Plugin.Instance.Log("F6 configuration saved; gameplay apply queued=" + pending); } catch (Exception ex) { foreach (KeyValuePair item2 in dictionary) { item2.Key.BoxedValue = item2.Value; } message = "Could not save configuration: " + ex.Message; Plugin.Instance.Error(message); } finally { config.SaveOnConfigSet = saveOnConfigSet; } float Value(string name) { ConfigEntryBase val = drafts.Keys.First((ConfigEntryBase e) => e.Definition.Key == name); object value2; return Convert.ToSingle(parsed.TryGetValue(val, out value2) ? value2 : val.BoxedValue, CultureInfo.InvariantCulture); } } internal static void Draw() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_048d: Unknown result type (might be due to invalid IL or missing references) if (!Open) { return; } Matrix4x4 matrix = GUI.matrix; float num = Mathf.Min(1f, Mathf.Min((float)Screen.width / 980f, (float)Screen.height / 740f)); GUI.matrix = Matrix4x4.Scale(new Vector3(num, num, 1f)); float num2 = (float)Screen.width / num; float num3 = (float)Screen.height / num; GUI.Box(new Rect(0f, 0f, num2, num3), ""); GUILayout.BeginArea(new Rect((num2 - 940f) / 2f, (num3 - 700f) / 2f, 940f, 700f), GUI.skin.box); GUILayout.Label("THE EAVESDROPPER / CONFIGURATION / F6 or Esc to close", Array.Empty()); GUILayout.Label(Authority ? "Host settings • changes affect this host's creatures" : "Client • only local accessibility is editable. Other values are this PC's saved settings, not the host's values.", Array.Empty()); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("Search", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(55f) }); search = GUILayout.TextField(search, Array.Empty()); GUILayout.EndHorizontal(); scroll = GUILayout.BeginScrollView(scroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(525f) }); string text = ""; ConfigEntryBase[] array = drafts.Keys.ToArray(); foreach (ConfigEntryBase val in array) { if (search.Length <= 0 || (val.Definition.Key + " " + val.Definition.Section + " " + val.Description.Description).IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0) { if (text != val.Definition.Section) { text = val.Definition.Section; GUILayout.Space(10f); GUILayout.Label("— " + text + " —", Array.Empty()); } bool enabled = GUI.enabled; GUI.enabled = Editable(val); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label(val.Definition.Key, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(330f) }); if (val.SettingType == typeof(bool)) { drafts[val] = GUILayout.Toggle(bool.TryParse(drafts[val], out var result) && result, "Enabled", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(155f) }).ToString(); } else { drafts[val] = GUILayout.TextField(drafts[val], (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(155f) }); } if (GUILayout.Button("Default", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) })) { drafts[val] = Text(val.DefaultValue); } AcceptableValueBase acceptableValues = val.Description.AcceptableValues; GUILayout.Label(((acceptableValues != null) ? acceptableValues.ToDescriptionString().Replace("# ", "") : null) ?? "", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(300f) }); GUILayout.EndHorizontal(); GUI.enabled = enabled; GUILayout.Label(val.Description.Description + ((val.Definition.Key == "Rarity") ? " RESTART REQUIRED." : ((val.Definition.Key == "AgitationInitial") ? " New enemies only." : "")), Array.Empty()); } } GUILayout.EndScrollView(); GUILayout.Label(message, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(50f) }); GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("Save & apply", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) })) { Save(); } if (GUILayout.Button("Discard edits", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) })) { Load(); message = "Unsaved edits discarded."; } if (GUILayout.Button("Close", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) })) { Close(); } GUILayout.EndHorizontal(); GUILayout.EndArea(); GUI.matrix = matrix; } } [HarmonyPatch] internal static class ConfigInputGuard { private static IEnumerable TargetMethods() { return from m in typeof(PlayerControllerB).GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) where m.Name.EndsWith("_performed", StringComparison.Ordinal) && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(CallbackContext) select m; } private static bool Prefix(PlayerControllerB __instance, MethodBase __originalMethod) { if (!ConfigMenu.Open || (Object)(object)GameNetworkManager.Instance?.localPlayerController != (Object)(object)__instance) { return true; } if (__originalMethod.Name == "OpenMenu_performed") { ConfigMenu.Close(); } return false; } } internal static class Configuration { private static readonly HashSet retired = new HashSet { "FixationWarning", "NoiseHuntSeconds", "NoiseAgitationThreshold", "AgitationDecay", "DoorLungeSeconds", "EchoMotionThreshold", "EchoHuntSeconds", "EchoInterval", "LoudNoisesToHunt", "DistractionLock", "ListenSeconds" }; internal static void BindAll(ConfigFile file, Settings values) { //IL_0450: Unknown result type (might be due to invalid IL or missing references) //IL_045a: Expected O, but got Unknown //IL_05fd: Unknown result type (might be due to invalid IL or missing references) //IL_0607: Expected O, but got Unknown FieldInfo[] fields = typeof(Settings).GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if (retired.Contains(fieldInfo.Name)) { continue; } string text = ((fieldInfo.Name == "Damage") ? "Combat" : "Tuning"); string text2 = ((fieldInfo.Name == "EchoIntervalStirred") ? "EchoInterval" : fieldInfo.Name); string text3; switch (fieldInfo.Name) { case "NoiseRange": text3 = "Maximum ordinary hearing radius in metres (HearingRadius)."; break; case "VoiceRange": text3 = "Speech hearing range in metres, capped by NoiseRange (VoiceDetectionRange)."; break; case "ObstructionMultiplier": text3 = "Ordinary hearing attenuation per obstruction (OccludedHearingMultiplier)."; break; case "FixationSeconds": text3 = "Listening window in seconds (FixationWindowSeconds); any audible speaker may confirm pursuit."; break; case "CompactPursuitSpeed": text3 = "Maximum folded/crawling pursuit speed in meters per second. Tight turns still slow movement. Default 6.5; existing RushSpeed remains the upper limit."; break; case "EchoDoorMultiplier": text3 = "Range multiplier through an open doorway (EchoDoorwayRangeMultiplier)."; break; case "EchoMovementThreshold": text3 = "Body displacement in metres between chirps, not speed or camera rotation."; break; case "AttackWarning": text3 = "Stationary attack telegraph duration in seconds before a direction-locked leap."; break; case "EchoIntervalIrritated": case "EchoIntervalEnraged": case "EchoIntervalStirred": case "EchoIntervalAngry": text3 = "Minimum seconds between sound-led scans at this agitation tier. A fresh heard lead and arrival are required; this does not schedule periodic scans."; break; default: text3 = (fieldInfo.Name.Contains("Multiplier") ? "Dimensionless tier/baseline multiplier." : ((fieldInfo.Name.Contains("Range") || fieldInfo.Name == "HallwayCommitDistance") ? "Metres." : (fieldInfo.Name.Contains("Speed") ? "Metres per second." : ((fieldInfo.Name.Contains("Seconds") || fieldInfo.Name.Contains("Interval") || fieldInfo.Name == "DistractionCooldown" || fieldInfo.Name == "PathTimeout") ? "Seconds." : ((fieldInfo.Name.Contains("PerSecond") || fieldInfo.Name.Contains("PerVoiceSecond") || fieldInfo.Name.Contains("PerNoiseSecond")) ? "Agitation points per audible second." : (fieldInfo.Name.StartsWith("Agitation") ? "Agitation points; ordinary gains scale with audibility." : "Host-authoritative behavior tuning; see docs/CONFIGURATION.md.")))))); break; } string text4 = text3; if (fieldInfo.FieldType == typeof(bool)) { fieldInfo.SetValue(values, file.Bind(text, text2, (bool)fieldInfo.GetValue(values), text4).Value); } else if (fieldInfo.FieldType == typeof(int)) { int num = ((fieldInfo.Name == "Damage") ? 100 : 10); fieldInfo.SetValue(values, file.Bind(text, text2, (int)fieldInfo.GetValue(values), new ConfigDescription(text4, (AcceptableValueBase)(object)new AcceptableValueRange(1, num), Array.Empty())).Value); } else if (!(fieldInfo.FieldType != typeof(float))) { float num2 = 0f; float num3 = 10000f; if (fieldInfo.Name.Contains("Seconds") || fieldInfo.Name.Contains("Interval") || fieldInfo.Name == "AttackWarning" || fieldInfo.Name == "LungeSeconds" || fieldInfo.Name == "PathTimeout" || fieldInfo.Name == "DistractionCooldown") { num2 = 0.05f; } if (fieldInfo.Name.Contains("Range") || fieldInfo.Name.Contains("Speed")) { num2 = 0.1f; num3 = 80f; } if (fieldInfo.Name.Contains("Multiplier")) { num2 = 0.05f; num3 = ((fieldInfo.Name.Contains("Obstruction") || fieldInfo.Name.Contains("Door")) ? 1 : 3); } if (fieldInfo.Name == "AgitationMaximum") { num2 = 1f; } if (fieldInfo.Name == "EchoMovementThreshold") { num2 = 0.01f; num3 = 2f; } if (fieldInfo.Name == "EchoWarningSeconds") { num2 = 0.2f; num3 = 5f; } float num4 = (float)fieldInfo.GetValue(values); float num5 = file.Bind(text, text2, num4, new ConfigDescription(text4, (AcceptableValueBase)(object)new AcceptableValueRange(num2, num3), Array.Empty())).Value; if (!float.IsFinite(num5)) { Plugin.Instance.Error($"Non-finite {text2}; using default {num4} for this session."); num5 = num4; } fieldInfo.SetValue(values, num5); } } float agitationMaximum = values.AgitationMaximum; if (!(values.AgitationIrritatedThreshold > 0f) || !(values.AgitationIrritatedThreshold < values.AgitationAngryThreshold) || !(values.AgitationAngryThreshold < values.AgitationEnragedThreshold) || !(values.AgitationEnragedThreshold < agitationMaximum)) { Plugin.Instance.Error("Agitation tier thresholds must be ascending and below AgitationMaximum. Using 20%, 45%, 75% of maximum for this session; saved entries unchanged."); values.AgitationIrritatedThreshold = agitationMaximum * 0.2f; values.AgitationAngryThreshold = agitationMaximum * 0.45f; values.AgitationEnragedThreshold = agitationMaximum * 0.75f; } values.AgitationInitial = Math.Clamp(values.AgitationInitial, 0f, agitationMaximum); } } public sealed class CreatureRig : MonoBehaviour { internal static readonly Creature Model = new Creature(); private static AdvancedVisual? advanced; private static bool checkedAsset; public Transform[] joints = Array.Empty(); private readonly Vector3[] positions = new Vector3[Model.Joints.Count]; private readonly Quaternion[] rotations = new Quaternion[Model.Joints.Count]; internal static GameObject Build(Transform parent) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Expected O, but got Unknown //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: 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_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Expected O, but got Unknown //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_046b: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("EavesdropperVisual"); val.transform.SetParent(parent, false); CreatureRig creatureRig = val.AddComponent(); creatureRig.joints = (Transform[])(object)new Transform[Model.Joints.Count]; for (int i = 0; i < creatureRig.joints.Length; i++) { Joint joint = Model.Joints[i]; GameObject val2 = new GameObject(joint.Name); val2.transform.SetParent((Transform)((joint.Parent < 0) ? ((object)val.transform) : ((object)creatureRig.joints[joint.Parent])), false); val2.transform.localPosition = V(joint.Position - ((joint.Parent < 0) ? Vector3.Zero : Model.Joints[joint.Parent].Position)); creatureRig.joints[i] = val2.transform; } Mesh val3 = new Mesh { name = "Eavesdropper sinew crawler — original skinned mesh" }; Vector3[] array = (Vector3[])(object)new Vector3[Model.Vertices.Count]; BoneWeight[] array2 = (BoneWeight[])(object)new BoneWeight[array.Length]; for (int j = 0; j < array.Length; j++) { Vertex vertex = Model.Vertices[j]; array[j] = V(vertex.Position); int num = j; BoneWeight val4 = default(BoneWeight); ((BoneWeight)(ref val4)).boneIndex0 = vertex.Joint; ((BoneWeight)(ref val4)).weight0 = 1f; array2[num] = val4; } Matrix4x4[] array3 = (Matrix4x4[])(object)new Matrix4x4[creatureRig.joints.Length]; for (int k = 0; k < array3.Length; k++) { array3[k] = Matrix4x4.Translate(-V(Model.Joints[k].Position)); } val3.vertices = array; val3.boneWeights = array2; val3.bindposes = array3; val3.subMeshCount = 3; for (int l = 0; l < 3; l++) { val3.SetTriangles(Model.Triangles[l], l); } val3.RecalculateNormals(); val3.RecalculateBounds(); SkinnedMeshRenderer val5 = val.AddComponent(); val5.sharedMesh = val3; val5.bones = creatureRig.joints; val5.rootBone = creatureRig.joints[0]; val5.updateWhenOffscreen = true; ((Renderer)val5).localBounds = new Bounds(Vector3.up, new Vector3(7f, 6f, 7f)); Shader val6 = Shader.Find("HDRP/Lit") ?? Shader.Find("Standard"); if ((Object)(object)val6 == (Object)null) { throw new InvalidOperationException("HDRP/Lit shader unavailable; supply the documented art bundle."); } Color[] array4 = (Color[])(object)new Color[3] { new Color(0.095f, 0.105f, 0.11f), new Color(0.012f, 0.004f, 0.004f), new Color(0.39f, 0.34f, 0.25f) }; Material[] array5 = (Material[])(object)new Material[3]; for (int m = 0; m < 3; m++) { Material val7 = new Material(val6); ((Object)val7).name = (new string[3] { "Charred sinew", "Facial cavity", "Worn claws" })[m]; Material val8 = val7; val8.SetColor("_BaseColor", array4[m]); if (val8.HasProperty("_Color")) { val8.SetColor("_Color", array4[m]); } if (val8.HasProperty("_Smoothness")) { val8.SetFloat("_Smoothness", (m == 0) ? 0.25f : 0.3f); } if (val8.HasProperty("_Metallic")) { val8.SetFloat("_Metallic", 0f); } array5[m] = val8; } ((Renderer)val5).sharedMaterials = array5; if (!checkedAsset) { checkedAsset = true; advanced = AdvancedVisual.Load(); } if (advanced != null) { val5.sharedMesh = advanced.Mesh; ((Renderer)val5).sharedMaterials = advanced.Materials; val5.quality = (SkinQuality)4; Object.Destroy((Object)(object)val3); Material[] array6 = array5; for (int n = 0; n < array6.Length; n++) { Object.Destroy((Object)(object)array6[n]); } } new GameObject("FacialSlit").transform.SetParent(val.transform, false); creatureRig.Apply("Dormant", 0f, instant: true); return val; } internal void Apply(string clip, float time, bool instant = false, float lookYaw = 0f, float agitation = 0f, float pulse = 0f) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: 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_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: 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_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) Model.Pose((clip == "DoorBash") ? "DoorWarn" : clip, time, positions, rotations, agitation); if (advanced != null) { advanced.Sample(clip, time, positions, rotations); } if (!instant && (Object)(object)StartOfRound.Instance != (Object)null) { string[] array = new string[2] { "L", "R" }; RaycastHit val5 = default(RaycastHit); foreach (string text in array) { Vector3 val = ((Component)this).transform.TransformPoint(V(Model.JointPosition("Hand" + text, positions, rotations))); Vector3 val2 = ((Component)this).transform.position + Vector3.up; Vector3 val3 = val + ((Component)this).transform.forward * 0.55f; val3.y = Mathf.Max(val3.y, ((Component)this).transform.position.y + 0.25f); Vector3 val4 = val3 - val2; if (((Vector3)(ref val4)).sqrMagnitude > 0.01f && Physics.SphereCast(val2, 0.18f, ((Vector3)(ref val4)).normalized, ref val5, ((Vector3)(ref val4)).magnitude, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1) && ((RaycastHit)(ref val5)).normal.y < 0.6f) { Vector3 val6 = ((Component)this).transform.InverseTransformPoint(val2 + ((Vector3)(ref val4)).normalized * Mathf.Max(0.05f, ((RaycastHit)(ref val5)).distance - 0.65f)); Model.RefitHand(text, new Vector3(val6.x, val6.y, val6.z), positions, rotations); } } } float num = (instant ? 1f : (1f - Mathf.Exp((float)(-((clip == "Dormant") ? 3 : 14)) * Time.deltaTime))); Quaternion val7 = default(Quaternion); for (int j = 0; j < joints.Length; j++) { joints[j].localPosition = Vector3.Lerp(joints[j].localPosition, V(positions[j]), num); Quaternion quaternion = rotations[j]; ((Quaternion)(ref val7))..ctor(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W); if (Model.Joints[j].Name == "Chest") { val7 = Quaternion.AngleAxis(pulse * 6f, Vector3.right) * val7; } if (advanced != null && Model.Joints[j].Name == "Chest") { val7 = Quaternion.AngleAxis(agitation * (2f + Mathf.Sin(time * 9f)), Vector3.right) * val7; } if (Model.Joints[j].Name == "Head") { val7 = Quaternion.AngleAxis(lookYaw, Vector3.up) * val7; } joints[j].localRotation = Quaternion.Slerp(joints[j].localRotation, val7, num); } } private static Vector3 V(Vector3 p) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return new Vector3(p.X, p.Y, p.Z); } } public sealed class EavesdropperAI : EnemyAI, IWorld { private sealed class EchoObject { public Transform Transform; public PlayerControllerB? Player; public GrabbableObject? Item; public Point First; public float Exposure; public bool Covered; } private DoorLock? doorApproach; private bool suppressDoorNoise; private Vector3 afterDoorGoal; private float doorDeadline; private float doorStarted; private bool doorOpened; private float nextAlternative; internal static readonly HashSet Live = new HashSet(); internal Brain Brain; internal Mode DisplayState; internal ulong DisplayTarget = ulong.MaxValue; internal float DisplayHunt; internal float DisplayWarning; internal bool DisplayRecovering; internal bool DisplayCrawling; internal bool DisplayDoorLunge; internal bool DisplayDoorBash; internal float DisplayDoorPhase; private float nextBestiaryRepair; internal float DisplayPhase; internal float DisplayAgitation; internal float MotionPhase; internal float DisplaySpeed; internal float EchoHeadYaw; internal float PulseFlashUntil; internal string NavigationStatus = "Waiting"; internal float HeardLevel; internal bool HeardVoice; internal readonly Dictionary VoiceReadings = new Dictionary(); private DoorLock[] doors = Array.Empty(); private float nextDoors; internal uint SnapshotSequence; internal uint LastSnapshot; internal uint LastDamage; internal Vector3 RemotePosition; internal Quaternion RemoteRotation; internal bool ReceivedSnapshot; internal bool HasBeenAwake; private float nextClientPath; private Vector3 clientCorner; private bool clientDetour; public Transform visualRoot; public Transform facialSlit; public AudioClip rustle; public AudioClip fixation; public AudioClip inhale; public AudioClip echoClick; public AudioClip echoPulse; internal uint HitSequence; public Animator? presentationAnimator; internal bool AnimatorHasAgitation; public CapsuleCollider bodyCollider; private float nextBehaviorLog; private Mode loggedMode; private float loggedAgitation = -1f; private float nextSnapshot; private float pathStarted; private float stuckSince; private Vector3 progressPosition; private bool started; private bool moving; private bool movementBlocked; private readonly NavMeshPath navPath = new NavMeshPath(); private readonly Collider[] attackColliders = (Collider[])(object)new Collider[32]; private readonly SoundEventGate soundEvents = new SoundEventGate(); private readonly RaycastHit[] hearingHits = (RaycastHit[])(object)new RaycastHit[16]; private readonly List echoObjects = new List(); private readonly StationaryEvidence stationary = new StationaryEvidence(); private bool finishingEcho; private readonly RaycastHit[] movementHits = (RaycastHit[])(object)new RaycastHit[24]; private readonly FailedRoutes failedRoutes = new FailedRoutes(); private readonly NavMeshPath legPath = new NavMeshPath(); private readonly List perceivedThreats = new List(); private readonly List routePoints = new List(); private readonly Dictionary soundMemory = new Dictionary(); private Vector3 travelGoal; private Vector3[] plannedCorners = Array.Empty(); private Vector3[] travelCorners = Array.Empty(); private int travelCorner; private float requestedSpeed; private float nextRepath; private float blockedFor; private float foldedUntil; private float nextClearance; private float nextDetour; private float nextRecovery; private float routeDeadline; private int recoveries; private Vector3 Ear => ((Component)this).transform.position + Vector3.up * 1.5f; Point IWorld.Position => P(((Component)this).transform.position); private int RoomMask => StartOfRound.Instance.collidersAndRoomMaskAndDefault; bool IWorld.Arrived { get { if ((Object)(object)doorApproach == (Object)null && !DisplayDoorBash && moving && travelCorner >= travelCorners.Length - 1 && !base.agent.pathPending) { return base.agent.remainingDistance <= 0.65f; } return false; } } bool IWorld.PathFailed { get { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)doorApproach != (Object)null || DisplayDoorBash) { return false; } if (!((Behaviour)base.agent).enabled || !base.agent.isOnNavMesh || movementBlocked) { return true; } if (Vector3.Distance(progressPosition, ((Component)this).transform.position) > 0.2f) { stuckSince = Time.time; progressPosition = ((Component)this).transform.position; } if (moving && ((!base.agent.pathPending && (int)base.agent.pathStatus != 0) || Time.time - stuckSince > 1.2f || Time.time > routeDeadline)) { if (Time.time <= routeDeadline && RecoverRoute()) { return false; } FailRoute("No travel progress after bounded recovery"); return true; } return false; } } private bool TryAlternateRoute(Vector3 desired, out Vector3 endpoint) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) endpoint = default(Vector3); if (Time.time < nextAlternative || base.allAINodes == null) { return false; } nextAlternative = Time.time + 1.5f; List list = new List(); GameObject[] allAINodes = base.allAINodes; foreach (GameObject val in allAINodes) { if ((Object)(object)val != (Object)null) { list.Add(val.transform.position); } } Vector3 start = ((Component)this).transform.position; list.Sort((Vector3 a, Vector3 b) => (Vector3.Distance(start, a) + Vector3.Distance(a, desired)).CompareTo(Vector3.Distance(start, b) + Vector3.Distance(b, desired))); float num = float.PositiveInfinity; Vector3[] array = null; for (int num2 = 0; num2 < Math.Min(12, list.Count); num2++) { Vector3 val2 = list[num2]; if (Vector3.Distance(start, val2) < 2f || !TryPathFrom(start, val2, navPath, out var endpoint2)) { continue; } Vector3[] collection = plannedCorners; if (TryPathFrom(endpoint2, desired, legPath, out var endpoint3)) { List list2 = new List(collection); for (int num3 = 1; num3 < plannedCorners.Length; num3++) { list2.Add(plannedCorners[num3]); } float num4 = 0f; for (int num5 = 1; num5 < list2.Count; num5++) { num4 += Vector3.Distance(list2[num5 - 1], list2[num5]); } if (num4 < num) { num = num4; array = list2.ToArray(); endpoint = endpoint3; } } } if (array == null) { return false; } plannedCorners = array; NavigationStatus = "Following reachable route via adjoining rooms"; return true; } private bool TryApproachDoor(Vector3 desired, float speed) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: 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_0106: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: 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) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: 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_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) NavMeshHit val = default(NavMeshHit); if (!NavMesh.SamplePosition(desired, ref val, 3.5f, base.agent.areaMask)) { return false; } NavMeshPath val2 = new NavMeshPath(); if (!base.agent.CalculatePath(((NavMeshHit)(ref val)).position, val2) || val2.corners.Length == 0) { return false; } Vector3 val3 = val2.corners[val2.corners.Length - 1]; DoorLock val4 = null; Vector3[] array = null; float num = float.PositiveInfinity; int num2 = 0; DoorLock[] array2 = doors; foreach (DoorLock val5 in array2) { if ((Object)(object)val5 == (Object)null || val5.isLocked) { continue; } NavMeshObstacle component = ((Component)val5).GetComponent(); if ((Object)(object)component == (Object)null || !((Behaviour)component).enabled) { continue; } bool flag = Vector3.Distance(val3, ((Component)val5).transform.position) < 3.5f; for (int j = 1; j < val2.corners.Length; j++) { if (flag) { break; } flag = NavigationPolicy.SegmentDistance(P(((Component)val5).transform.position), P(val2.corners[j - 1]), P(val2.corners[j])) < 1.5f; } if (!flag || num2++ >= 8 || (Object)(object)((Component)val5).GetComponent() == (Object)null) { continue; } for (int k = 0; k < 8; k++) { float num3 = (float)k * MathF.PI / 4f; Vector3 desired2 = ((Component)val5).transform.position + new Vector3(Mathf.Cos(num3), 0f, Mathf.Sin(num3)) * 1.6f; if (!TryPath(desired2, navPath, out var endpoint)) { continue; } Vector3 step = ((Component)val5).transform.position - endpoint; step.y = 0f; if (!BodyHit(endpoint, step, out var nearest, compact: true) || (!((Object)(object)((RaycastHit)(ref nearest)).collider == (Object)null) && !((Object)(object)((Component)((RaycastHit)(ref nearest)).collider).GetComponentInParent() != (Object)(object)val5))) { float num4 = 0f; for (int l = 1; l < plannedCorners.Length; l++) { num4 += Vector3.Distance(plannedCorners[l - 1], plannedCorners[l]); } if (num4 < num) { num = num4; val4 = val5; array = plannedCorners; } } } } if ((Object)(object)val4 == (Object)null || array == null) { return false; } doorApproach = val4; afterDoorGoal = desired; requestedSpeed = speed; travelCorners = array; travelCorner = 1; travelGoal = array[^1]; base.agent.isStopped = false; base.agent.speed = Mathf.Min(speed, 4f); moving = SetLeg(); movementBlocked = false; blockedFor = 0f; doorDeadline = Time.time + Mathf.Max(10f, num / Mathf.Max(1f, base.agent.speed) * 2f + 5f); doorStarted = -1f; doorOpened = false; if (!moving) { doorApproach = null; return false; } NavigationStatus = "Approaching closed ordinary door on route to sound"; return true; } private bool UpdateDoorInteraction() { //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: 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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: 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_022e: Unknown result type (might be due to invalid IL or missing references) //IL_024e: 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_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)doorApproach == (Object)null) { return false; } Mode state = Brain.State; bool flag = ((state == Mode.Dormant || state - 6 <= Mode.Fixated) ? true : false); if (flag || base.stunNormalizedTimer > 0f || base.stunnedIndefinitely > 0 || Time.time > doorDeadline) { doorApproach = null; DisplayDoorBash = false; FailRoute("Door interaction interrupted or timed out"); return false; } DoorLock val = doorApproach; if (val.isLocked) { FailRoute("Door became locked"); return false; } if (doorStarted < 0f) { if (Vector3.Distance(((Component)this).transform.position, ((Component)val).transform.position) > 2.3f) { return false; } Vector3 val2 = ((Component)val).transform.position - ((Component)this).transform.position; val2.y = 0f; if (BodyHit(((Component)this).transform.position, val2, out var nearest, compact: true) && ((Object)(object)((RaycastHit)(ref nearest)).collider == (Object)null || (Object)(object)((Component)((RaycastHit)(ref nearest)).collider).GetComponentInParent() != (Object)(object)val)) { return false; } doorStarted = Time.time; base.agent.isStopped = true; base.agent.nextPosition = ((Component)this).transform.position; if (((Vector3)(ref val2)).sqrMagnitude > 0.01f) { ((Component)this).transform.rotation = Quaternion.LookRotation(val2); } } DisplayDoorBash = true; DisplayDoorPhase = Time.time - doorStarted; DisplaySpeed = 0f; DisplayCrawling = true; base.agent.nextPosition = ((Component)this).transform.position; stuckSince = Time.time; if (!doorOpened && DisplayDoorPhase >= 0.5f) { doorOpened = true; NavMeshObstacle component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null && ((Behaviour)component).enabled) { suppressDoorNoise = true; try { ((Component)val).GetComponent().TriggerAnimationNonPlayer(true, true, false); } finally { suppressDoorNoise = false; } val.OpenDoorAsEnemy(true); val.OpenDoorAsEnemyClientRpc(); } } if (DisplayDoorPhase >= 1.2f) { Vector3 v = afterDoorGoal; float speed = requestedSpeed; doorApproach = null; DisplayDoorBash = false; moving = false; if (!((IWorld)this).Move(P(v), speed)) { movementBlocked = true; } } return true; } public override void Awake() { } public override void Start() { //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: 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_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Invalid comparison between Unknown and I4 if (!((NetworkBehaviour)this).IsSpawned || (Object)(object)RoundManager.Instance == (Object)null) { return; } ((EnemyAI)this).Awake(); ((EnemyAI)this).Start(); base.movingTowardsTargetPlayer = false; base.moveTowardsDestination = false; started = true; Live.Add(this); if ((Object)(object)presentationAnimator != (Object)null) { AnimatorControllerParameter[] parameters = presentationAnimator.parameters; foreach (AnimatorControllerParameter val in parameters) { if (val.name == "Agitation" && (int)val.type == 1) { AnimatorHasAgitation = true; } } } Brain = new Brain(Plugin.Settings, this); ((Behaviour)base.agent).enabled = ((NetworkBehaviour)this).IsServer; base.agent.updatePosition = false; base.agent.updateRotation = false; base.agent.radius = 0.55f; base.agent.autoBraking = true; base.agent.autoRepath = true; base.agent.stoppingDistance = 0.08f; base.agent.obstacleAvoidanceType = (ObstacleAvoidanceType)4; base.ventAnimationFinished = true; base.postStunInvincibilityTimer = -1f; NavMeshHit val2 = default(NavMeshHit); if (((NetworkBehaviour)this).IsServer && !base.agent.isOnNavMesh && NavMesh.SamplePosition(((Component)this).transform.position, ref val2, 3f, base.agent.areaMask)) { base.agent.Warp(((NavMeshHit)(ref val2)).position); } if (((NetworkBehaviour)this).IsServer && !base.agent.isOnNavMesh) { Plugin.Instance.Log("Eavesdropper spawn had no nearby NavMesh; despawning safely."); ((NetworkBehaviour)this).NetworkObject.Despawn(true); return; } RepairBestiary(); RemotePosition = ((Component)this).transform.position; RemoteRotation = ((Component)this).transform.rotation; progressPosition = ((Component)this).transform.position; stuckSince = Time.time; if (((NetworkBehaviour)this).IsServer) { ((IWorld)this).Stop(); } } public override void Update() { //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Unknown result type (might be due to invalid IL or missing references) //IL_0462: Unknown result type (might be due to invalid IL or missing references) //IL_0468: Unknown result type (might be due to invalid IL or missing references) //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_0553: Unknown result type (might be due to invalid IL or missing references) //IL_0569: Unknown result type (might be due to invalid IL or missing references) //IL_03fc: Unknown result type (might be due to invalid IL or missing references) //IL_0402: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_0422: Unknown result type (might be due to invalid IL or missing references) //IL_042a: Unknown result type (might be due to invalid IL or missing references) //IL_042f: Unknown result type (might be due to invalid IL or missing references) //IL_0436: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_0450: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_03e9: Unknown result type (might be due to invalid IL or missing references) if (!started || !((NetworkBehaviour)this).IsSpawned) { return; } if (Time.time >= nextBestiaryRepair) { nextBestiaryRepair = Time.time + 2f; RepairBestiary(); } if (((NetworkBehaviour)this).IsServer) { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null && RoundLifetime.ShouldDespawn(((NetworkBehaviour)this).IsServer, ((NetworkBehaviour)this).IsSpawned, instance.shipIsLeaving, instance.inShipPhase, instance.allPlayersDead)) { ((IWorld)this).Stop(); SessionWire.Forget(((NetworkBehaviour)this).NetworkObjectId); ((NetworkBehaviour)this).NetworkObject.Despawn(true); return; } if (Time.time >= nextDoors) { doors = Object.FindObjectsOfType(); nextDoors = Time.time + 5f; } UpdateClearance(); if (!UpdateDoorInteraction()) { ApplyAgentMovement(); } if (base.stunnedIndefinitely <= 0) { base.stunNormalizedTimer -= Time.deltaTime / Math.Max(0.01f, base.enemyType.stunTimeMultiplier); } if (base.stunNormalizedTimer < 0f) { base.postStunInvincibilityTimer -= Time.deltaTime * 5f; } if (base.stunnedIndefinitely > 0 && !SessionWire.Valid(base.stunnedByPlayer)) { base.stunnedIndefinitely = 0; } Brain.Tick(Time.deltaTime, base.stunNormalizedTimer > 0f || base.stunnedIndefinitely > 0); CopyDisplay(); if (Time.time >= nextBehaviorLog) { nextBehaviorLog = Time.time + 1f; if (Plugin.Settings.DebugBehaviorLogging && loggedMode != Brain.State) { Plugin.Instance.Log($"Enemy {((NetworkBehaviour)this).NetworkObjectId}: {loggedMode} -> {Brain.State}, confidence={Brain.Confidence:F2}, persistence={Brain.HuntRemaining:F1}s"); } if (Plugin.Settings.DebugAgitationLogging && Mathf.Abs(loggedAgitation - Brain.Agitation) >= 1f) { Plugin.Instance.Log($"Enemy {((NetworkBehaviour)this).NetworkObjectId}: agitation={Brain.Agitation:F1}, tier={Brain.Tier}, dormant inactivity={Brain.RestSeconds:F1}s"); } loggedMode = Brain.State; loggedAgitation = Brain.Agitation; } if (Time.time >= nextSnapshot) { nextSnapshot = Time.time + 0.1f; SessionWire.Snapshot(this); } } else if (ReceivedSnapshot) { Vector3 val = Vector3.Lerp(((Component)this).transform.position, RemotePosition, 1f - Mathf.Exp(-18f * Time.deltaTime)); if (!BodyHit(((Component)this).transform.position, val - ((Component)this).transform.position, out var nearest)) { ((Component)this).transform.position = val; } else { if (Time.time >= nextClientPath) { nextClientPath = Time.time + 0.2f; clientDetour = NavMesh.CalculatePath(((Component)this).transform.position, RemotePosition, -1, navPath) && (int)navPath.status == 0 && navPath.corners.Length > 1; if (clientDetour) { clientCorner = navPath.corners[1]; } } if (clientDetour) { Vector3 val2 = Vector3.MoveTowards(((Component)this).transform.position, clientCorner, Mathf.Max(1f, DisplaySpeed) * Time.deltaTime); if (!BodyHit(((Component)this).transform.position, val2 - ((Component)this).transform.position, out nearest)) { ((Component)this).transform.position = val2; } } } ((Component)this).transform.rotation = Quaternion.Slerp(((Component)this).transform.rotation, RemoteRotation, 1f - Mathf.Exp(-18f * Time.deltaTime)); DisplayHunt = Mathf.Max(0f, DisplayHunt - Time.deltaTime); DisplayWarning = Mathf.Max(0f, DisplayWarning - Time.deltaTime); DisplayPhase += Time.deltaTime; if (DisplayDoorBash) { DisplayDoorPhase += Time.deltaTime; } if (DisplaySpeed > 0.08f) { MotionPhase += Time.deltaTime; } } if ((Object)(object)bodyCollider != (Object)null) { bodyCollider.height = (DisplayCrawling ? 1.65f : 2.45f); bodyCollider.radius = 0.55f; bodyCollider.center = Vector3.up * (bodyCollider.height * 0.5f); } EchoHeadYaw = Mathf.MoveTowards(EchoHeadYaw, 0f, Time.deltaTime * 180f); Presentation.Pose(this); } internal void CopyDisplay() { DisplayState = Brain.State; DisplayTarget = Brain.Target; DisplayHunt = Brain.HuntRemaining; DisplayWarning = Brain.WarningRemaining; DisplayRecovering = Brain.Recovering; DisplayDoorLunge = Brain.DoorLunge; DisplayPhase = Brain.StateSeconds; DisplayAgitation = Brain.Agitation; base.currentBehaviourStateIndex = (int)DisplayState; } private void RepairBestiary() { Terminal val = Object.FindObjectOfType(); if (!((Object)(object)val == (Object)null) && !((Object)(object)Plugin.Bestiary == (Object)null) && val.enemyFiles.Contains(Plugin.Bestiary)) { int creatureFileID = Plugin.Bestiary.creatureFileID; ScanNodeProperties[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].creatureScanID = creatureFileID; } } } public override void DoAIInterval() { } public override void OnCollideWithPlayer(Collider other) { } public override void SetEnemyStunned(bool setToStunned, float setToStunTime = 1f, PlayerControllerB? setStunnedByPlayer = null) { if (started && ((NetworkBehaviour)this).IsServer) { ((EnemyAI)this).SetEnemyStunned(setToStunned, setToStunTime, setStunnedByPlayer); } } public override void HitEnemy(int force = 1, PlayerControllerB? playerWhoHit = null, bool playHitSFX = false, int hitID = -1) { //IL_0023: 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_0040: 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) //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) if (started && ((NetworkBehaviour)this).IsServer && SessionWire.Valid(playerWhoHit) && force >= 1 && !(Vector3.Distance(((Component)this).transform.position, ((Component)playerWhoHit).transform.position) > 4f) && !Blocked(Ear, ((Component)playerWhoHit).transform.position + Vector3.up)) { ((EnemyAI)this).SetEnemyStunned(true, 0.6f, playerWhoHit); } } public override void DetectNoise(Vector3 noisePosition, float noiseLoudness, int timesPlayedInSameSpot = 0, int noiseID = 0) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) if (started && ((NetworkBehaviour)this).IsServer && !GameSoundHooks.InSourceCallback && !suppressDoorNoise && noiseID != 1974301 && noiseID != 75 && noiseID != 6 && Finite(noisePosition) && float.IsFinite(noiseLoudness) && !(noiseLoudness < Plugin.Settings.NoiseThreshold) && soundEvents.Accept(noiseID, P(noisePosition), Time.time, 0.15f)) { HeardSound(SoundKind.Ordinary, (ulong)noiseID, noisePosition, Plugin.Settings.NoiseRange, noiseLoudness, 0.15f, ulong.MaxValue); } } internal void HeardSound(SoundKind kind, ulong source, Vector3 position, float range, float loudness, float duration, ulong player = ulong.MaxValue) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (!started || !((NetworkBehaviour)this).IsServer) { return; } float num = Audibility(position + Vector3.up * 0.5f, range, loudness); if (!(num <= 0f)) { if (!Brain.SensorySuppressed) { RememberSound(position, source); } Brain.Sound(kind, source, P(position), num, duration, player); } } internal void Repellent(ulong source, Vector3 position, float loudness, bool initial, float duration) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (!started || !((NetworkBehaviour)this).IsServer) { return; } float num = Audibility(position + Vector3.up * 0.5f, Plugin.Settings.ContinuousNoiseRange, loudness); if (num <= 0f) { return; } if (initial) { RememberSound(position, source); Brain.Scare(P(position)); } if (duration > 0f) { if (Brain.SensorySuppressed || Brain.State == Mode.Retreating) { Brain.Irritation(num, duration); } else { Brain.Sound(SoundKind.Ordinary, source, P(position), num, duration, ulong.MaxValue); } } } internal void Voice(PlayerControllerB player, ushort amplitude, float credit) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) if (!started || !((NetworkBehaviour)this).IsServer) { return; } HeardLevel = VoiceActivity.Level(amplitude, Plugin.Settings.VoiceSensitivity); HeardVoice = false; if (HeardLevel < Plugin.Settings.VoiceThreshold) { VoiceReadings[player.actualClientId] = (HeardLevel, false); return; } Vector3 position = ((Component)player).transform.position; float num = Audibility(position + Vector3.up * 1.5f, Plugin.Settings.VoiceRange, 1f); HeardVoice = num > 0f && !Brain.SensorySuppressed; VoiceReadings[player.actualClientId] = (HeardLevel, HeardVoice); if (HeardVoice) { RememberSound(position, player.actualClientId); } Brain.Sound(SoundKind.Voice, player.actualClientId, P(position), num, credit, player.actualClientId); } private float Audibility(Vector3 point, float range, float level) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_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_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_004b: 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) range = Mathf.Min(range, Plugin.Settings.NoiseRange); float num = Vector3.Distance(Ear, point); if (range <= 0f || num > range || level <= 0f) { return 0f; } Vector3 ear = Ear; Vector3 val = point - Ear; int num2 = Physics.RaycastNonAlloc(ear, ((Vector3)(ref val)).normalized, hearingHits, num, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1); HashSet hashSet = new HashSet(); for (int i = 0; i < num2; i++) { if ((Object)(object)((RaycastHit)(ref hearingHits[i])).collider != (Object)null) { hashSet.Add(((Object)((RaycastHit)(ref hearingHits[i])).collider).GetInstanceID()); } } float num3 = Mathf.Pow(Plugin.Settings.ObstructionMultiplier, (float)Mathf.Min(4, hashSet.Count)); float num4 = range * num3; if (num > num4) { return 0f; } return Mathf.Clamp01(level) * num3 * Mathf.Max(0.05f, 1f - num / Mathf.Max(0.1f, num4)); } internal static bool Blocked(Vector3 a, Vector3 b) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)StartOfRound.Instance == (Object)null)) { return Physics.Linecast(a, b, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1); } return true; } internal static bool Finite(Vector3 p) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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) if (float.IsFinite(p.x) && float.IsFinite(p.y)) { return float.IsFinite(p.z); } return false; } internal static Point P(Vector3 v) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return new Point(v.x, v.y, v.z); } internal static Vector3 V(Point p) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) return new Vector3(p.X, p.Y, p.Z); } bool IWorld.ValidPlayer(ulong id) { return (Object)(object)SessionWire.FindPlayer(id) != (Object)null; } private DoorLock? NearbyDoor() { //IL_0026: 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) DoorLock[] array = doors; foreach (DoorLock val in array) { if (!((Object)(object)val == (Object)null) && !val.isLocked && !(Vector3.Distance(((Component)this).transform.position, ((Component)val).transform.position) > 2.1f)) { NavMeshObstacle component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null && !((Behaviour)component).enabled) { return val; } } } return null; } void IWorld.Face(Point aim) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0038: Unknown result type (might be due to invalid IL or missing references) Vector3 val = V(aim) - ((Component)this).transform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude > 0.01f) { ((Component)this).transform.rotation = Quaternion.LookRotation(val); } } bool IWorld.AttackOpportunity(Point aim) { return (Object)(object)CloseVictim(aim) != (Object)null; } private PlayerControllerB? CloseVictim(Point aim) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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_0045: 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) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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_00ad: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) int num = Physics.OverlapSphereNonAlloc(Ear, Plugin.Settings.AttackRange, attackColliders, StartOfRound.Instance.playersMask, (QueryTriggerInteraction)2); PlayerControllerB result = null; float num2 = float.MaxValue; Vector3 val = V(aim) - ((Component)this).transform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { val = ((Component)this).transform.forward; } for (int i = 0; i < num; i++) { PlayerControllerB componentInParent = ((Component)attackColliders[i]).GetComponentInParent(); if (SessionWire.Valid(componentInParent)) { Vector3 val2 = ((Component)componentInParent).transform.position + Vector3.up; Vector3 val3 = val2 - Ear; Vector3 val4 = val3; val4.y = 0f; if (!(Vector3.Angle(val, val4) > 60f) && !(((Vector3)(ref val3)).magnitude > Plugin.Settings.AttackRange) && !Blocked(Ear, val2) && ((Vector3)(ref val3)).sqrMagnitude < num2) { result = componentInParent; num2 = ((Vector3)(ref val3)).sqrMagnitude; } } } return result; } bool IWorld.Strike(Point aim, int damage) { if (!((NetworkBehaviour)this).IsServer || Brain.State != Mode.Attacking || base.stunNormalizedTimer > 0f || base.stunnedIndefinitely > 0) { return false; } PlayerControllerB val = CloseVictim(aim); if ((Object)(object)val != (Object)null) { return SessionWire.Damage(this, val, damage); } return false; } void IWorld.Search(Point center, float speed) { //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) //IL_00bf: 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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_0057: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (base.allAINodes != null && base.allAINodes.Length != 0) { int num = Random.Range(0, base.allAINodes.Length); for (int i = 0; i < Math.Min(12, base.allAINodes.Length); i++) { GameObject val = base.allAINodes[(num + i) % base.allAINodes.Length]; if (!((Object)(object)val == (Object)null)) { Vector3 position = val.transform.position; if (!(Vector3.Distance(position, V(center)) > 18f) && !(Vector3.Distance(position, ((Component)this).transform.position) < 2f) && ((IWorld)this).Move(P(position), speed)) { return; } } } } Vector2 val2 = Random.insideUnitCircle * 5f; ((IWorld)this).Move(new Point(center.X + val2.x, center.Y, center.Z + val2.y), speed); } void IWorld.Signal(Cue cue) { if (cue == Cue.EchoWarning) { PrepareEcho(); } CopyDisplay(); SessionWire.Signal(this, cue); } public override void OnDestroy() { Live.Remove(this); if (started) { SessionWire.Forget(((NetworkBehaviour)this).NetworkObjectId); } if (started && (Object)(object)RoundManager.Instance != (Object)null) { ((EnemyAI)this).OnDestroy(); } } private void PrepareEcho() { echoObjects.Clear(); NavigationStatus = "Echo preparation: ears spread, throat rattle"; } void IWorld.CancelEcho() { echoObjects.Clear(); if (!finishingEcho) { stationary.Clear(); } finishingEcho = false; } bool IWorld.EchoReady() { return SessionWire.EchoReady(this); } void IWorld.EchoFirst() { //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) echoObjects.Clear(); PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (SessionWire.Valid(val) && SessionWire.EchoWarned(this, val.actualClientId)) { echoObjects.Add(new EchoObject { Transform = ((Component)val).transform, Player = val }); } } GrabbableObject[] array = Object.FindObjectsOfType(); foreach (GrabbableObject val2 in array) { if ((Object)(object)val2 != (Object)null && val2.isInFactory && !val2.isHeld && !val2.isHeldByEnemy && Vector3.Distance(((Component)this).transform.position, ((Component)val2).transform.position) < Plugin.Settings.EchoRange + 2f) { echoObjects.Add(new EchoObject { Transform = ((Component)val2).transform, Item = val2 }); } } foreach (EchoObject echoObject in echoObjects) { echoObject.First = P(echoObject.Transform.position); echoObject.Exposure = Exposure(echoObject.Transform.position, (Object)(object)echoObject.Item != (Object)null); echoObject.Covered = Clutter(echoObject.Transform.position); } NavigationStatus = "First chirp sampled; waiting for second"; } private float Exposure(Vector3 point, bool item) { //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010b: 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_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0184: 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_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: 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_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: 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_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_0131: 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) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0073: 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) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: 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_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) float num = Plugin.Settings.EchoRange; DoorLock[] array = doors; foreach (DoorLock val in array) { if ((Object)(object)val == (Object)null || val.isLocked) { continue; } NavMeshObstacle component = ((Component)val).GetComponent(); if (!((Object)(object)component == (Object)null) && !((Behaviour)component).enabled) { Vector3 val2 = point - ((Component)this).transform.position; float num2 = Vector3.Dot(((Component)val).transform.position - ((Component)this).transform.position, val2) / Mathf.Max(0.001f, ((Vector3)(ref val2)).sqrMagnitude); if (num2 > 0f && num2 < 1f && NavigationPolicy.SegmentDistance(P(((Component)val).transform.position), P(((Component)this).transform.position), P(point)) < 1.1f) { num *= Plugin.Settings.EchoDoorMultiplier; break; } } } if (Vector3.Distance(Ear, point + Vector3.up * (float)((!item) ? 1 : 0)) > num) { return 0f; } if (item) { return (!Blocked(Ear, point)) ? 1 : 0; } int num3 = 0; Vector3[] array2 = (Vector3[])(object)new Vector3[5] { point + Vector3.up * 1.55f, point + Vector3.up, point + Vector3.up * 0.45f, point + Vector3.up + Vector3.right * 0.22f, point + Vector3.up - Vector3.right * 0.22f }; foreach (Vector3 val3 in array2) { bool flag = !Blocked(Ear, val3); if (flag) { num3++; } if (Plugin.Settings.DebugEchoVisualization) { Debug.DrawLine(Ear, val3, flag ? Color.green : Color.red, 1f); } } return (float)num3 / 5f; } private bool Clutter(Vector3 point) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_0017: 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) int num = 0; Vector3 val = point + Vector3.up * 0.9f; Vector3 val2 = default(Vector3); for (int i = 0; i < 8; i++) { float num2 = (float)i * MathF.PI / 4f; ((Vector3)(ref val2))..ctor(Mathf.Cos(num2), 0f, Mathf.Sin(num2)); if (Physics.Raycast(val, val2, 1.2f, RoomMask, (QueryTriggerInteraction)1)) { num++; } } return num >= 3; } EchoResult IWorld.EchoTarget() { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) stationary.Begin(); EchoResult result = default(EchoResult); float num = float.NegativeInfinity; foreach (EchoObject echoObject in echoObjects) { if ((Object)(object)echoObject.Transform == (Object)null) { continue; } bool flag = (Object)(object)echoObject.Item != (Object)null; if ((flag && (echoObject.Item.isHeld || echoObject.Item.isHeldByEnemy || !echoObject.Item.isInFactory)) || (!flag && !SessionWire.Valid(echoObject.Player))) { continue; } Vector3 position = echoObject.Transform.position; float num2 = Mathf.Min(echoObject.Exposure, Exposure(position, flag)); bool flag2 = Point.Distance(echoObject.First, P(position)) >= Plugin.Settings.EchoMovementThreshold; bool clear = num2 >= 0.8f; bool flag3 = false; if (!flag) { flag3 = stationary.Observe(echoObject.Player.actualClientId, clear, echoObject.Covered || Clutter(position), flag2, Plugin.Settings.EchoStationaryConfirmations); } if (!(num2 <= 0f) && (!flag || flag2)) { float num3 = (flag ? 1.35f : (flag3 ? 1.2f : 0.45f)) / (1f + Vector3.Distance(((Component)this).transform.position, position)); if (!(num3 <= num)) { num = num3; result = new EchoResult(P(position), flag ? ulong.MaxValue : echoObject.Player.actualClientId, flag3); } } } stationary.End(); finishingEcho = true; echoObjects.Clear(); NavigationStatus = ((!result.Found) ? "Pulse pair: no exposed return" : (result.Confirmed ? "Pulse pair: confirmed prey snapshot" : "Pulse pair: uncertain shape/item lead")); return result; } void IWorld.LookAtEcho(Point position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) Vector3 val = V(position) - ((Component)this).transform.position; val.y = 0f; EchoHeadYaw = Mathf.Clamp(Vector3.SignedAngle(((Component)this).transform.forward, val, Vector3.up), -80f, 80f); } int IWorld.Leap(Point aim, float distance) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0023: 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_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) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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) Vector3 val = ((Component)this).transform.forward * Mathf.Max(0f, distance); if (BodyHit(((Component)this).transform.position, val, out var _, DisplayCrawling)) { ((IWorld)this).Stop(); return -1; } Vector3 val2 = ((Component)this).transform.position + val; NavMeshHit val3 = default(NavMeshHit); NavMeshHit val4 = default(NavMeshHit); if (NavMesh.Raycast(((Component)this).transform.position, val2, ref val3, base.agent.areaMask) || !NavMesh.SamplePosition(val2, ref val4, 0.2f, base.agent.areaMask)) { return 1; } ((Component)this).transform.position = ((NavMeshHit)(ref val4)).position; base.agent.nextPosition = ((NavMeshHit)(ref val4)).position; DisplaySpeed = distance / Mathf.Max(0.001f, Time.deltaTime); return 0; } bool IWorld.Rest(out Point destination) { //IL_0007: 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) destination = P(((Component)this).transform.position); if (((IWorld)this).TryRetreat(out destination)) { return true; } destination = P(((Component)this).transform.position); return false; } private void RememberSound(Vector3 source, ulong id = ulong.MaxValue) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) soundMemory[id] = (P(source), Time.time); } internal void ForgetSound(ulong id) { soundMemory.Remove(id); } bool IWorld.ContinueStraight(float speed) { //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_0025: 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_0036: 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_0038: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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_0060: 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) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) Vector3 forward = ((Component)this).transform.forward; forward.y = 0f; ((Vector3)(ref forward)).Normalize(); Vector3 position = ((Component)this).transform.position; float num = Plugin.Settings.HallwayCommitDistance; NavMeshHit val = default(NavMeshHit); if (NavMesh.Raycast(position, position + forward * num, ref val, base.agent.areaMask)) { num = Mathf.Max(0f, Vector3.Distance(position, ((NavMeshHit)(ref val)).position) - 0.8f); } if (BodyHit(position, forward * num, out var nearest, compact: true)) { num = Mathf.Max(0f, ((RaycastHit)(ref nearest)).distance - 0.15f); } if (num < 1f) { return false; } NavigationStatus = "Continuing last approach heading; no new sound"; return ((IWorld)this).Move(P(position + forward * num), speed); } private void UpdateClearance() { //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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_00e3: 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_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_010b: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) if (Time.time >= nextClearance) { nextClearance = Time.time + 0.1f; Vector3 val; if (!moving) { val = Vector3.zero; } else { Vector3 desiredVelocity = base.agent.desiredVelocity; val = ((Vector3)(ref desiredVelocity)).normalized * 0.9f; } Vector3 val2 = val; if (!StandingRoom(((Component)this).transform.position) || !StandingRoom(((Component)this).transform.position + val2) || (Object)(object)NearbyDoor() != (Object)null) { foldedUntil = Time.time + 1f; } } DisplayCrawling = Time.time < foldedUntil; base.agent.height = (DisplayCrawling ? 1.65f : 2.45f); if (moving) { float num = requestedSpeed; Vector3 val3 = base.agent.steeringTarget - ((Component)this).transform.position; val3.y = 0f; if (Vector3.Angle(((Component)this).transform.forward, val3) > 40f) { num = Mathf.Min(num, 2.5f); } if (DisplayCrawling && Brain.State != Mode.Attacking) { num = Mathf.Min(num, (Brain.State == Mode.Rushing) ? Plugin.Settings.CompactPursuitSpeed : 4f); } base.agent.speed = num; } } private bool StandingRoom(Vector3 position) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: 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_0010: 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_0025: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) return !Physics.CheckBox(position + Vector3.up * 1.25f + ((Component)this).transform.forward * 0.2f, new Vector3(1.4f, 1.15f, 1.4f), ((Component)this).transform.rotation, RoomMask, (QueryTriggerInteraction)1); } private bool BodyHit(Vector3 start, Vector3 step, out RaycastHit nearest, bool compact = false) { //IL_0001: 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_0040: 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_0055: 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) //IL_0070: 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_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) nearest = default(RaycastHit); float magnitude = ((Vector3)(ref step)).magnitude; if (magnitude < 0.0001f || (Object)(object)StartOfRound.Instance == (Object)null) { return false; } float num = ((compact || DisplayCrawling) ? 1.65f : 2.45f); int num2 = Physics.CapsuleCastNonAlloc(start + Vector3.up * 0.65f, start + Vector3.up * (num - 0.52f), 0.52f, step / magnitude, movementHits, magnitude + 0.025f, RoomMask, (QueryTriggerInteraction)1); bool result = num2 == movementHits.Length; float num3 = float.MaxValue; for (int i = 0; i < num2; i++) { RaycastHit val = movementHits[i]; if (!(((RaycastHit)(ref val)).normal.y >= 0.65f) && (!(step.y > 0.02f) || !(((RaycastHit)(ref val)).point.y < start.y + 0.3f)) && ((RaycastHit)(ref val)).distance < num3) { nearest = val; num3 = ((RaycastHit)(ref val)).distance; result = true; } } return result; } private void ApplyAgentMovement() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: 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_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_0237: 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_00ff: 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) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) if (!((Behaviour)base.agent).enabled || !base.agent.isOnNavMesh) { return; } Vector3 position = ((Component)this).transform.position; Vector3 val = base.agent.nextPosition - position; if (!moving) { base.agent.nextPosition = position; DisplaySpeed = 0f; return; } if (!base.agent.pathPending && base.agent.remainingDistance < 0.45f && travelCorner < travelCorners.Length - 1) { travelCorner++; if (!SetLeg()) { FailRoute("Next corridor leg became blocked"); return; } } if (BodyHit(position, val, out var nearest)) { Vector3 val2 = Vector3.ProjectOnPlane(val, ((RaycastHit)(ref nearest)).normal); val2.y = val.y; Vector3 val3 = position + val2; NavMeshHit val4 = default(NavMeshHit); if (((Vector3)(ref val2)).sqrMagnitude > 1E-05f) { Vector3 normal = ((RaycastHit)(ref nearest)).normal; NavMeshHit val5 = default(NavMeshHit); if (((Vector3)(ref normal)).sqrMagnitude > 0.5f && NavMesh.SamplePosition(val3, ref val4, 0.12f, base.agent.areaMask) && !NavMesh.Raycast(position, ((NavMeshHit)(ref val4)).position, ref val5, base.agent.areaMask) && !BodyHit(position, ((NavMeshHit)(ref val4)).position - position, out var _)) { ((Component)this).transform.position = ((NavMeshHit)(ref val4)).position; } } base.agent.nextPosition = ((Component)this).transform.position; blockedFor += Time.deltaTime; if (blockedFor > 0.3f && !RecoverRoute()) { FailRoute("No clear detour around room geometry"); } } else { ((Component)this).transform.position = base.agent.nextPosition; blockedFor = 0f; } Vector3 val6 = ((Component)this).transform.position - position; DisplaySpeed = ((Vector3)(ref val6)).magnitude / Mathf.Max(0.001f, Time.deltaTime); MotionPhase += ((Vector3)(ref val6)).magnitude / Mathf.Max(1f, requestedSpeed); Vector3 val7 = val6; val7.y = 0f; if (((Vector3)(ref val7)).sqrMagnitude > 1E-05f && Brain.State != Mode.Attacking) { ((Component)this).transform.rotation = Quaternion.RotateTowards(((Component)this).transform.rotation, Quaternion.LookRotation(val7), 500f * Time.deltaTime); } } private void FailRoute(string reason) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) failedRoutes.Add(P(travelGoal), Time.time); NavigationStatus = reason; movementBlocked = true; blockedFor = 0f; ((IWorld)this).Stop(); } private bool TryPath(Vector3 desired, NavMeshPath path, out Vector3 endpoint, bool allowDetour = false) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) return TryPathFrom(((Component)this).transform.position, desired, path, out endpoint, allowDetour); } private bool TryPathFrom(Vector3 start, Vector3 desired, NavMeshPath path, out Vector3 endpoint, bool allowDetour = false) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: 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_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: 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_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) endpoint = default(Vector3); RaycastHit val = default(RaycastHit); if (Physics.Raycast(desired + Vector3.up * 0.15f, Vector3.down, ref val, 3.5f, RoomMask, (QueryTriggerInteraction)1) && ((RaycastHit)(ref val)).normal.y > 0.65f) { desired = ((RaycastHit)(ref val)).point; } NavMeshHit val2 = default(NavMeshHit); if (!Finite(desired) || !((Behaviour)base.agent).enabled || !base.agent.isOnNavMesh || !NavMesh.SamplePosition(desired, ref val2, 1.25f, base.agent.areaMask)) { return false; } Vector3 val3 = ((NavMeshHit)(ref val2)).position - desired; val3.y = 0f; if (((Vector3)(ref val3)).magnitude > 0.6f || Mathf.Abs(((NavMeshHit)(ref val2)).position.y - desired.y) > 1.25f || Blocked(desired + Vector3.up * 0.2f, ((NavMeshHit)(ref val2)).position + Vector3.up * 0.2f)) { return false; } if (!NavMesh.CalculatePath(start, ((NavMeshHit)(ref val2)).position, base.agent.areaMask, path) || (int)path.status != 0) { return false; } Vector3[] corners = path.corners; if (corners.Length < 2) { return false; } for (int i = 1; i < corners.Length; i++) { if (!CenterCorner(corners[i], out corners[i])) { return false; } } List list = new List { corners[0] }; bool flag = false; for (int j = 1; j < corners.Length; j++) { Vector3 val4 = list[list.Count - 1]; Vector3 val5 = corners[j]; if (ClearSegment(val4, val5)) { list.Add(val5); continue; } if (!allowDetour || flag || Time.time < nextDetour) { return false; } nextDetour = Time.time + 0.75f; flag = true; if (!FindDetour(val4, val5, out List route)) { return false; } for (int k = 1; k < route.Count; k++) { list.Add(V(route[k])); } } plannedCorners = list.ToArray(); endpoint = ((corners.Length != 0) ? corners[^1] : ((NavMeshHit)(ref val2)).position); return corners.Length >= 2; } private bool ClearSegment(Vector3 a, Vector3 b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_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) NavMeshHit val = default(NavMeshHit); RaycastHit nearest; if (!NavMesh.Raycast(a, b, ref val, base.agent.areaMask)) { return !BodyHit(a, b - a, out nearest, compact: true); } return false; } private bool FindDetour(Vector3 start, Vector3 end, out List route) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) route = null; Vector3 val = (start + end) * 0.5f; NavMeshHit val3 = default(NavMeshHit); if (BodyHit(start, end - start, out var nearest, compact: true)) { Vector3 val2 = end - start; val = start + ((Vector3)(ref val2)).normalized * Mathf.Max(0f, ((RaycastHit)(ref nearest)).distance); } else if (NavMesh.Raycast(start, end, ref val3, base.agent.areaMask)) { val = ((NavMeshHit)(ref val3)).position; } List list = new List { P(start), P(end) }; NavMeshHit val4 = default(NavMeshHit); for (int i = -4; i <= 4; i++) { for (int j = -4; j <= 4; j++) { if (NavMesh.SamplePosition(val + new Vector3((float)i * 0.8f, 0f, (float)j * 0.8f), ref val4, 0.25f, base.agent.areaMask) && !(Mathf.Abs(((NavMeshHit)(ref val4)).position.y - val.y) > 0.5f) && CompactRoom(((NavMeshHit)(ref val4)).position)) { list.Add(P(((NavMeshHit)(ref val4)).position)); } } } List list2 = LocalDetour.Find(list, (Point a, Point b) => ClearSegment(V(a), V(b))); if (list2 == null) { return false; } route = list2; NavigationStatus = "Following capsule-clear obstacle bypass"; return true; } private bool RecoverRoute() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) if (recoveries >= 2) { return false; } if (Time.time < nextRecovery || Time.time < nextDetour) { base.agent.nextPosition = ((Component)this).transform.position; return true; } nextRecovery = Time.time + 1f; recoveries++; if (!TryPath(travelGoal, navPath, out var _, allowDetour: true)) { return false; } travelCorners = plannedCorners; travelCorner = 1; base.agent.nextPosition = ((Component)this).transform.position; base.agent.isStopped = false; moving = SetLeg(); blockedFor = 0f; movementBlocked = !moving; stuckSince = Time.time; progressPosition = ((Component)this).transform.position; if (moving) { NavigationStatus = "Recovered route to last detected position"; } return moving; } private bool CompactRoom(Vector3 p) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: 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_0010: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) return !Physics.CheckCapsule(p + Vector3.up * 0.65f, p + Vector3.up * 1.13f, 0.55f, RoomMask, (QueryTriggerInteraction)1); } private bool CenterCorner(Vector3 corner, out Vector3 result) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) result = corner; if (CompactRoom(corner)) { return true; } float[] array = new float[5] { 0.3f, 0.6f, 0.9f, 1.2f, 1.5f }; NavMeshHit val = default(NavMeshHit); NavMeshHit val2 = default(NavMeshHit); foreach (float num in array) { for (int j = 0; j < 12; j++) { float num2 = (float)j * MathF.PI / 6f; if (NavMesh.SamplePosition(corner + new Vector3(Mathf.Cos(num2), 0f, Mathf.Sin(num2)) * num, ref val, 0.15f, base.agent.areaMask) && !(Mathf.Abs(((NavMeshHit)(ref val)).position.y - corner.y) > 0.3f) && !NavMesh.Raycast(corner, ((NavMeshHit)(ref val)).position, ref val2, base.agent.areaMask) && CompactRoom(((NavMeshHit)(ref val)).position)) { result = ((NavMeshHit)(ref val)).position; return true; } } } return false; } private bool SetLeg() { //IL_0012: 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) if (base.agent.CalculatePath(travelCorners[travelCorner], legPath) && (int)legPath.status == 0) { return base.agent.SetPath(legPath); } return false; } bool IWorld.Move(Point point, float speed) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_007e: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0102: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) Vector3 val = V(point); if (failedRoutes.Contains(point, Time.time)) { NavigationStatus = "Recently blocked destination; waiting/reselecting"; return false; } if ((Object)(object)doorApproach != (Object)null) { afterDoorGoal = val; requestedSpeed = speed; return true; } if (moving && Vector3.Distance(travelGoal, val) < 0.7f && (Brain.State == Mode.Retreating || Time.time < nextRepath)) { return true; } if (!TryPath(val, navPath, out var endpoint, allowDetour: true) && !TryAlternateRoute(val, out endpoint)) { if (TryApproachDoor(val, speed)) { return true; } failedRoutes.Add(point, Time.time); NavigationStatus = "No complete room-clear path"; ((IWorld)this).Stop(); return false; } if (!moving || Vector3.Distance(travelGoal, endpoint) > 1f) { pathStarted = Time.time; stuckSince = Time.time; progressPosition = ((Component)this).transform.position; recoveries = 0; } float num = 0f; for (int i = 1; i < plannedCorners.Length; i++) { num += Vector3.Distance(plannedCorners[i - 1], plannedCorners[i]); } routeDeadline = Time.time + Mathf.Max(Plugin.Settings.PathTimeout, num / Mathf.Max(1f, Mathf.Min(speed, 4f)) * 2f + 5f); nextRepath = Time.time + 0.35f; travelGoal = endpoint; requestedSpeed = speed; blockedFor = 0f; movementBlocked = false; base.agent.isStopped = false; base.agent.speed = (DisplayCrawling ? Mathf.Min(speed, (Brain.State == Mode.Rushing) ? Plugin.Settings.CompactPursuitSpeed : 4f) : speed); travelCorners = plannedCorners; travelCorner = 1; moving = SetLeg(); NavigationStatus = (moving ? "Following complete path" : "Path assignment failed"); return moving; } void IWorld.Stop() { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) doorApproach = null; DisplayDoorBash = false; moving = false; DisplaySpeed = 0f; if ((Object)(object)base.agent != (Object)null && ((Behaviour)base.agent).enabled && base.agent.isOnNavMesh) { base.agent.isStopped = true; base.agent.ResetPath(); base.agent.velocity = Vector3.zero; base.agent.nextPosition = ((Component)this).transform.position; } } bool IWorld.TryRetreat(out Point destination) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) destination = default(Point); perceivedThreats.Clear(); foreach (var value in soundMemory.Values) { if (Time.time - value.Time < 20f && Point.Distance(P(((Component)this).transform.position), value.Position) < Plugin.Settings.RetreatRange) { perceivedThreats.Add(value.Position); } } if (perceivedThreats.Count == 0) { return false; } if (moving && Brain.State == Mode.Retreating) { routePoints.Clear(); routePoints.Add(P(((Component)this).transform.position)); for (int i = travelCorner; i < travelCorners.Length; i++) { routePoints.Add(P(travelCorners[i])); } if (float.IsFinite(NavigationPolicy.RetreatScore(routePoints, perceivedThreats, cover: false))) { destination = P(travelGoal); return true; } } float best = float.NegativeInfinity; Vector3 refuge = default(Vector3); if (base.allAINodes != null) { GameObject[] allAINodes = base.allAINodes; foreach (GameObject val in allAINodes) { if ((Object)(object)val != (Object)null) { Consider(val.transform.position); } } } for (int k = 0; k < 12; k++) { float num = (float)k * MathF.PI / 6f; float[] array = new float[2] { 5f, 9f }; foreach (float num2 in array) { Consider(((Component)this).transform.position + new Vector3(Mathf.Cos(num), 0f, Mathf.Sin(num)) * num2); } } if (!float.IsFinite(best)) { NavigationStatus = "Cornered: no safe retreat route"; if (moving && Brain.State == Mode.Retreating) { ((IWorld)this).Stop(); movementBlocked = true; } return false; } destination = P(refuge); return true; void Consider(Vector3 candidate) { //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_0028: 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_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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_010b: 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) float num3 = Vector3.Distance(((Component)this).transform.position, candidate); if (!(num3 < 2f) && !(num3 > 24f) && !failedRoutes.Contains(P(candidate), Time.time) && TryPath(candidate, navPath, out var endpoint)) { routePoints.Clear(); Vector3[] array2 = plannedCorners; foreach (Vector3 v in array2) { routePoints.Add(P(v)); } bool cover = true; foreach (Point perceivedThreat in perceivedThreats) { if (!Blocked(V(perceivedThreat) + Vector3.up, endpoint + Vector3.up)) { cover = false; break; } } float num4 = NavigationPolicy.RetreatScore(routePoints, perceivedThreats, cover); if (num4 > best) { best = num4; refuge = endpoint; } } } } } internal static class GameSoundHooks { internal static int Depth; private static readonly SoundEventGate gate = new SoundEventGate(); private static readonly ActivationGate activations = new ActivationGate(); private static readonly Dictionary lastSample = new Dictionary(); private static GrabbableObject[] items = Array.Empty(); private static float nextItems; private static float nextSample; internal static bool InSourceCallback => Depth > 0; private static bool Server { get { if ((Object)(object)NetworkManager.Singleton != (Object)null) { return NetworkManager.Singleton.IsServer; } return false; } } internal static void Install() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) new Harmony("jeepg.eavesdropper.sounds").PatchAll(typeof(GameSoundHooks).Assembly); } internal static void Clear() { items = Array.Empty(); lastSample.Clear(); activations.Clear(); nextItems = (nextSample = 0f); Depth = 0; } private static ulong Id(GrabbableObject item) { return (ulong)((uint)((Object)item).GetInstanceID() | long.MinValue); } private static string Name(GrabbableObject item) { return (item.itemProperties?.itemName ?? ((Object)item).name).ToLowerInvariant().Replace(" ", ""); } private static bool Repels(GrabbableObject item) { string text = Name(item); Settings settings = Plugin.Settings; if (!settings.HornRepels || !text.Contains("horn")) { if (settings.BlowdryerRepels) { if (!text.Contains("blowdryer")) { return text.Contains("hairdryer"); } return true; } return false; } return true; } internal static void Footstep(PlayerControllerB player) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) if (!Server || !SessionWire.Valid(player) || !gate.Accept(((Object)player).GetInstanceID(), EavesdropperAI.P(((Component)player).transform.position), Time.time, 0.18f)) { return; } int num; if (!((NetworkBehaviour)player).IsOwner) { if ((Object)(object)player.playerBodyAnimator != (Object)null) { AnimatorStateInfo currentAnimatorStateInfo = player.playerBodyAnimator.GetCurrentAnimatorStateInfo(0); num = (((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsTag("Sprinting") ? 1 : 0); } else { num = 0; } } else { num = (player.isSprinting ? 1 : 0); } bool flag = (byte)num != 0; bool isCrouching = player.isCrouching; SoundKind kind = ((!isCrouching) ? ((!flag) ? SoundKind.Walk : SoundKind.Run) : SoundKind.Crouch); Settings settings = Plugin.Settings; float range = (isCrouching ? settings.CrouchFootstepRange : (flag ? settings.RunFootstepRange : settings.WalkFootstepRange)); foreach (EavesdropperAI item in EavesdropperAI.Live) { item.HeardSound(kind, player.actualClientId, ((Component)player).transform.position, range, 1f, 0f, player.actualClientId); } } internal static void Activated(NoisemakerProp item) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (!Server || (Object)(object)item.noiseAudio == (Object)null || !item.noiseAudio.isPlaying) { return; } bool flag = activations.Rising(Id((GrabbableObject)(object)item), on: true); if (!(Repels((GrabbableObject)(object)item) && flag)) { return; } foreach (EavesdropperAI item2 in EavesdropperAI.Live) { item2.Repellent(Id((GrabbableObject)(object)item), ((Component)item).transform.position, 1f, initial: true, 0f); } } internal static void Dropped(EventWhenDroppedItem item) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) if (!Server || (Object)(object)item.itemAudio == (Object)null || !item.itemAudio.isPlaying || ((GrabbableObject)item).isHeld || ((GrabbableObject)item).isHeldByEnemy || !gate.Accept(((Object)item).GetInstanceID(), EavesdropperAI.P(((Component)item).transform.position), Time.time, 0.3f)) { return; } bool flag = Plugin.Settings.DroppedBellRepels && Name((GrabbableObject)(object)item).Contains("bell"); foreach (EavesdropperAI item2 in EavesdropperAI.Live) { if (flag) { item2.Repellent(Id((GrabbableObject)(object)item), ((Component)item).transform.position, item.noiseLoudness, initial: true, 0f); } else { item2.HeardSound(SoundKind.Ordinary, Id((GrabbableObject)(object)item), ((Component)item).transform.position, item.noiseRange, item.noiseLoudness, 0.15f, ulong.MaxValue); } } } internal static void Tick() { //IL_01cd: 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) if (!Server || Time.time < nextSample) { return; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || instance.shipIsLeaving || instance.inShipPhase || instance.allPlayersDead) { Clear(); return; } nextSample = Time.time + 0.1f; if (Time.time >= nextItems) { items = Object.FindObjectsOfType(); nextItems = Time.time + 3f; } GrabbableObject[] array = items; foreach (GrabbableObject val in array) { if ((Object)(object)val == (Object)null) { continue; } AudioSource val2 = null; float loudness = 1f; AnimatedItem val3 = (AnimatedItem)(object)((val is AnimatedItem) ? val : null); if (val3 != null) { val2 = val3.itemAudio; loudness = val3.noiseLoudness; } else { NoisemakerProp val4 = (NoisemakerProp)(object)((val is NoisemakerProp) ? val : null); if (val4 != null) { val2 = val4.noiseAudio; } else { BoomboxItem val5 = (BoomboxItem)(object)((val is BoomboxItem) ? val : null); if (val5 == null) { continue; } val2 = val5.boomboxAudio; } } int instanceID = ((Object)val).GetInstanceID(); lastSample.TryGetValue(instanceID, out var value); lastSample[instanceID] = Time.time; bool flag = (Object)(object)val2 != (Object)null && val2.isPlaying && val2.volume > 0.001f; bool initial = activations.Rising(Id(val), flag); if (!flag) { continue; } float duration = ((value > 0f) ? Mathf.Clamp(Time.time - value, 0f, 0.25f) : 0f); foreach (EavesdropperAI item in EavesdropperAI.Live) { if (Repels(val)) { item.Repellent(Id(val), ((Component)val).transform.position, loudness, initial, duration); } else { item.HeardSound(SoundKind.Ordinary, Id(val), ((Component)val).transform.position, Plugin.Settings.ContinuousNoiseRange, loudness, duration, ulong.MaxValue); } } } } } [HarmonyPatch(typeof(AnimatedItem), "Update")] internal static class AnimatedSoundScope { private static void Prefix(out bool __state) { __state = true; GameSoundHooks.Depth++; } private static void Finalizer(bool __state) { if (__state) { GameSoundHooks.Depth = Math.Max(0, GameSoundHooks.Depth - 1); } } } [HarmonyPatch(typeof(BoomboxItem), "Update")] internal static class MusicSoundScope { private static void Prefix(out bool __state) { __state = true; GameSoundHooks.Depth++; } private static void Finalizer(bool __state) { if (__state) { GameSoundHooks.Depth = Math.Max(0, GameSoundHooks.Depth - 1); } } } [HarmonyPatch(typeof(NoisemakerProp), "ItemActivate")] internal static class NoisemakerSoundHook { private static void Prefix(out bool __state) { __state = true; GameSoundHooks.Depth++; } private static void Postfix(NoisemakerProp __instance) { GameSoundHooks.Activated(__instance); } private static void Finalizer(bool __state) { if (__state) { GameSoundHooks.Depth = Math.Max(0, GameSoundHooks.Depth - 1); } } } [HarmonyPatch(typeof(EventWhenDroppedItem), "PlayDropSFX")] internal static class BellSoundHook { private static void Prefix(out bool __state) { __state = true; GameSoundHooks.Depth++; } private static void Postfix(EventWhenDroppedItem __instance) { GameSoundHooks.Dropped(__instance); } private static void Finalizer(bool __state) { if (__state) { GameSoundHooks.Depth = Math.Max(0, GameSoundHooks.Depth - 1); } } } [HarmonyPatch(typeof(PlayerControllerB), "PlayFootstepSound")] internal static class FootstepSoundHook { private static void Postfix(PlayerControllerB __instance) { GameSoundHooks.Footstep(__instance); } } [BepInPlugin("jeepg.eavesdropper", "The Eavesdropper", "0.6.2")] [BepInDependency("evaisa.lethallib", "1.2.0")] public sealed class Plugin : BaseUnityPlugin { public const string Id = "jeepg.eavesdropper"; internal static Plugin Instance; internal static Settings Settings; internal static ConfigEntry DebugSpawn; internal static EnemyType Enemy; internal static TerminalNode Bestiary; private void Awake() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown Instance = this; Settings = new Settings(); Configuration.BindAll(((BaseUnityPlugin)this).Config, Settings); int value = ((BaseUnityPlugin)this).Config.Bind("Spawn", "Rarity", 20, new ConfigDescription("Indoor relative spawn weight; zero disables natural spawning.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 1000), Array.Empty())).Value; DebugSpawn = ((BaseUnityPlugin)this).Config.Bind("Testing", "EnableF8Spawn", false, "Host only: F8 spawns one at a hidden reachable indoor node. Use in a test save."); Enemy = PrototypeFactory.Create(); TerminalNode val = ScriptableObject.CreateInstance(); val.displayText = "THE EAVESDROPPER\n\nRisk classification: Occupational.\nRepeated conversation may be interpreted as a request for individual service. Three clicks indicate assignment. Remain silent and relocate quietly. A colleague may redirect service using approved loud equipment. A throat rattle precedes two inspection chirps. Remain still and use substantial cover; repeated clear inspections can identify stationary personnel. Moving loose equipment may redirect inspection. Closed doors provide cover. An agitated specimen follows the latest audible position. Silent changes of direction may interrupt service. Injuries sustained during unnecessary discussion are not reimbursable.\n\n"; val.clearPreviousText = true; val.creatureName = "The Eavesdropper"; val.maxCharactersToType = 35; Bestiary = val; TerminalKeyword val2 = ScriptableObject.CreateInstance(); val2.word = "eavesdropper"; Enemies.RegisterEnemy(Enemy, value, (LevelTypes)(-1), val, val2); GameSoundHooks.Install(); RuntimeBootstrap.Install(); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"The Eavesdropper 0.6.2 registered. Scene bootstrap installed; F8 enabled={DebugSpawn.Value}."); } private void Bind(string key, ref float value, float min, float max, string description) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown value = ((BaseUnityPlugin)this).Config.Bind("Tuning", key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange(min, max), Array.Empty())).Value; } internal void Log(string message) { ((BaseUnityPlugin)this).Logger.LogInfo((object)message); } internal void Error(string message) { ((BaseUnityPlugin)this).Logger.LogError((object)message); } } internal static class Presentation { internal static void Cue(EavesdropperAI e, Cue cue) { AudioClip val; switch (cue) { case Eavesdropper.Core.Cue.EchoWarning: val = e.echoClick; break; case Eavesdropper.Core.Cue.EchoPulse: case Eavesdropper.Core.Cue.EchoFirst: val = e.echoPulse; break; case Eavesdropper.Core.Cue.Fixation: val = e.fixation; break; case Eavesdropper.Core.Cue.Attack: case Eavesdropper.Core.Cue.Breath: val = e.inhale; break; case Eavesdropper.Core.Cue.Rustle: case Eavesdropper.Core.Cue.Wake: case Eavesdropper.Core.Cue.Repelled: case Eavesdropper.Core.Cue.WallImpact: val = e.rustle; break; default: val = null; break; } AudioClip val2 = val; if ((Object)(object)((EnemyAI)e).creatureSFX != (Object)null && (Object)(object)val2 != (Object)null) { ((EnemyAI)e).creatureSFX.PlayOneShot(val2, (cue == Eavesdropper.Core.Cue.Breath) ? (0.08f + 0.17f * e.DisplayAgitation / Mathf.Max(1f, Plugin.Settings.AgitationMaximum)) : 1f); } if ((cue == Eavesdropper.Core.Cue.EchoPulse || cue == Eavesdropper.Core.Cue.EchoFirst) ? true : false) { e.PulseFlashUntil = Time.time + 0.18f; } } internal static void Pose(EavesdropperAI e) { //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) if (e.DisplayState != Mode.Dormant) { e.HasBeenAwake = true; } bool flag = e.DisplayState == Mode.Rushing; bool flag2 = e.DisplayState == Mode.Attacking; CreatureRig component = ((Component)e.visualRoot).GetComponent(); if ((Object)(object)component != (Object)null) { string text; switch (e.DisplayState) { case Mode.Dormant: text = ((e.HasBeenAwake && e.DisplayPhase < 1.2f) ? "Rest" : "Dormant"); break; case Mode.Returning: text = ((e.DisplaySpeed > 0.08f) ? "Retreat" : "Rest"); break; case Mode.Wandering: if (e.DisplayPhase < 1.2f && e.DisplaySpeed < 0.08f) { text = "Wake"; break; } goto default; case Mode.Echolocating: text = (e.DisplayCrawling ? "EchoWarnCompact" : "EchoWarn"); break; case Mode.Stunned: text = "Stunned"; break; case Mode.Retreating: text = ((e.DisplayPhase < 0.5f) ? "Repelled" : "Retreat"); break; case Mode.Fixated: text = "Fixated"; break; case Mode.Attacking: text = (e.DisplayRecovering ? "Recover" : ((!e.DisplayDoorLunge) ? (e.DisplayCrawling ? "DoorWarn" : "Warn") : (e.DisplayCrawling ? "DoorLunge" : "Lunge"))); break; default: text = (e.DisplayCrawling ? "DoorCrawl" : ((e.DisplaySpeed < 0.08f) ? "Listen" : (flag ? "Sprint" : ((e.DisplayState == Mode.Investigating) ? "Investigate" : "Wander")))); break; } string text2 = text; bool flag3; switch (text2) { case "Sprint": case "Retreat": case "DoorCrawl": case "Wander": case "Investigate": flag3 = true; break; default: flag3 = false; break; } float time = (flag3 ? e.MotionPhase : e.DisplayPhase); if (e.DisplayDoorBash) { text2 = "DoorBash"; time = e.DisplayDoorPhase; } component.Apply(text2, time, instant: false, flag2 ? 0f : e.EchoHeadYaw, e.DisplayAgitation / Mathf.Max(1f, Plugin.Settings.AgitationMaximum), Mathf.Clamp01((e.PulseFlashUntil - Time.time) / 0.18f)); } else { Vector3 localScale = e.facialSlit.localScale; localScale.x = Mathf.Lerp(localScale.x, flag2 ? 0.22f : 0.035f, Time.deltaTime * 18f); e.facialSlit.localScale = localScale; } if ((Object)(object)e.presentationAnimator != (Object)null && (Object)(object)e.presentationAnimator.runtimeAnimatorController != (Object)null) { e.presentationAnimator.SetInteger("State", (int)e.DisplayState); if (e.AnimatorHasAgitation) { e.presentationAnimator.SetFloat("Agitation", e.DisplayAgitation / Mathf.Max(1f, Plugin.Settings.AgitationMaximum)); } e.presentationAnimator.SetBool("Rushing", flag); e.presentationAnimator.SetBool("SlitOpen", flag2); e.presentationAnimator.SetBool("Stunned", e.DisplayState == Mode.Stunned); e.presentationAnimator.SetBool("Crawling", e.DisplayCrawling); e.presentationAnimator.SetBool("DoorLunge", e.DisplayDoorLunge && flag2); e.presentationAnimator.SetBool("Recovering", e.DisplayRecovering); e.presentationAnimator.SetBool("Warning", flag2 && !e.DisplayDoorLunge && !e.DisplayRecovering); e.presentationAnimator.SetFloat("Phase", e.DisplayPhase); e.presentationAnimator.SetFloat("Speed", Mathf.Clamp01(e.DisplaySpeed / 9f)); } } internal static void Diagnostics() { //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Expected O, but got Unknown //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) if (!SessionWire.Diagnostics) { return; } string text = "EAVESDROPPER / F7 DIAGNOSTICS\n" + SessionWire.VoiceStatus; foreach (EavesdropperAI item in EavesdropperAI.Live) { text += $"\n#{((NetworkBehaviour)item).NetworkObjectId} {item.DisplayState} agitation={item.DisplayAgitation:F1}/{Plugin.Settings.AgitationMaximum:F0} folded={item.DisplayCrawling} speed={item.DisplaySpeed:F1}"; if (!((NetworkBehaviour)item).IsServer) { continue; } text = text + $"\n Confidence={item.Brain.Confidence:F2} persistence={item.Brain.HuntRemaining:F1}s dormant inactivity={item.Brain.RestSeconds:F1}s\n Navigation: " + item.NavigationStatus; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (SessionWire.Valid(val)) { text += $"\n {val.playerUsername}: voice {item.Brain.Progress(val.actualClientId):F1}/{Plugin.Settings.SpeechSeconds:F1}s"; text += (item.VoiceReadings.TryGetValue(val.actualClientId, out (float, bool) value) ? $" level={value.Item1:F4}, audible={value.Item2}" : " no accepted report"); } } } GUIStyle val2 = new GUIStyle(GUI.skin.box) { fontSize = 16, alignment = (TextAnchor)0, wordWrap = true }; val2.normal.textColor = Color.white; GUI.Box(new Rect(16f, 16f, (float)Mathf.Min(900, Screen.width - 32), (float)(200 + EavesdropperAI.Live.Count * 75)), text, val2); } } internal static class PrototypeFactory { private static AssetBundle? artBundle; internal static EnemyType Create() { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: 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_0193: Expected O, but got Unknown //IL_01aa: 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_01c1: 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_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: 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) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Expected O, but got Unknown //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) EnemyType val = ScriptableObject.CreateInstance(); ((Object)val).name = "EavesdropperType"; val.enemyName = "The Eavesdropper"; val.isOutsideEnemy = false; val.isDaytimeEnemy = false; val.PowerLevel = 2f; val.DiversityPowerLevel = 1; val.MaxCount = 2; val.spawnInGroupsOf = 1; val.probabilityCurve = AnimationCurve.Linear(0f, 0.3f, 1f, 1f); val.numberSpawnedFalloff = AnimationCurve.Linear(0f, 1f, 1f, 1f); val.canBeStunned = true; val.canDie = false; val.canBeDestroyed = false; val.stunTimeMultiplier = 1f; val.stunGameDifficultyMultiplier = 1f; val.doorSpeedMultiplier = 0f; val.EnemySize = (EnemySize)2; val.SizeLimit = (NavSizeLimit)1; val.WaterType = (EnemyWaterType)0; val.audioClips = Array.Empty(); val.miscAnimations = Array.Empty(); GameObject val2 = NetworkPrefabs.CreateNetworkPrefab("JeepG.Eavesdropper.Prototype.v1"); val2.layer = 19; NavMeshAgent val3 = val2.AddComponent(); val3.radius = 0.36f; val3.height = 2.7f; val3.speed = 2.2f; val3.acceleration = 35f; val3.angularSpeed = 500f; val3.stoppingDistance = 0.35f; val3.autoTraverseOffMeshLink = false; EavesdropperAI eavesdropperAI = val2.AddComponent(); ((EnemyAI)eavesdropperAI).agent = val3; ((EnemyAI)eavesdropperAI).enemyType = val; ((EnemyAI)eavesdropperAI).enemyHP = 5; ((EnemyAI)eavesdropperAI).AIIntervalTime = 0.2f; ((EnemyAI)eavesdropperAI).enemyBehaviourStates = (EnemyBehaviourState[])(object)new EnemyBehaviourState[12]; for (int i = 0; i < ((EnemyAI)eavesdropperAI).enemyBehaviourStates.Length; i++) { ((EnemyAI)eavesdropperAI).enemyBehaviourStates[i] = new EnemyBehaviourState(); } GameObject val4 = new GameObject("Collision"); val4.transform.SetParent(val2.transform, false); val4.layer = 19; CapsuleCollider val5 = val4.AddComponent(); ((Collider)val5).isTrigger = true; val5.height = 2.7f; val5.radius = 0.4f; val5.center = Vector3.up * 1.35f; eavesdropperAI.bodyCollider = val5; Rigidbody obj = val4.AddComponent(); obj.isKinematic = true; obj.useGravity = false; EnemyAICollisionDetect obj2 = val4.AddComponent(); obj2.mainScript = (EnemyAI)(object)eavesdropperAI; obj2.alwaysAllowHitting = true; GameObject val6 = new GameObject("ScanNode") { layer = 22 }; val6.transform.SetParent(val2.transform, false); val6.transform.localPosition = Vector3.up * 1.7f; BoxCollider obj3 = val6.AddComponent(); ((Collider)obj3).isTrigger = true; obj3.size = Vector3.one * 0.5f; ScanNodeProperties obj4 = val6.AddComponent(); obj4.headerText = "The Eavesdropper"; obj4.subText = "Occupational listening hazard"; obj4.nodeType = 1; obj4.maxRange = 20; obj4.minRange = 1; obj4.requiresLineOfSight = true; obj4.creatureScanID = -1; GameObject val7 = new GameObject("Ear"); val7.transform.SetParent(val2.transform, false); val7.transform.localPosition = Vector3.up * 2f; ((EnemyAI)eavesdropperAI).eye = val7.transform; ((EnemyAI)eavesdropperAI).creatureSFX = val7.AddComponent(); ((EnemyAI)eavesdropperAI).creatureVoice = val2.AddComponent(); AudioSource[] array = (AudioSource[])(object)new AudioSource[2] { ((EnemyAI)eavesdropperAI).creatureSFX, ((EnemyAI)eavesdropperAI).creatureVoice }; foreach (AudioSource obj5 in array) { obj5.playOnAwake = false; obj5.spatialBlend = 1f; obj5.rolloffMode = (AudioRolloffMode)1; obj5.minDistance = 1f; obj5.maxDistance = Mathf.Max(35f, Plugin.Settings.EchoRange + 4f); obj5.dopplerLevel = 0f; } eavesdropperAI.rustle = Synth("Ear rustle", 0.4f, 0); eavesdropperAI.fixation = Synth("Three dry fixation clicks", 1.15f, 1); eavesdropperAI.inhale = Synth("Lunge inhale", 0.65f, 2); eavesdropperAI.echoClick = Synth("Throat rattle before echo pair", 0.65f, 3); eavesdropperAI.echoPulse = Synth("Hollow echolocation chirp", 0.55f, 4); val.stunSFX = eavesdropperAI.rustle; GameObject val8 = LoadArt(val2.transform); if ((Object)(object)val8 == (Object)null) { val8 = BuildVisual(val2.transform); } eavesdropperAI.visualRoot = val8.transform; eavesdropperAI.facialSlit = val8.transform.Find("FacialSlit"); if ((Object)(object)eavesdropperAI.facialSlit == (Object)null) { throw new InvalidDataException("Eavesdropper visual requires direct child FacialSlit."); } eavesdropperAI.presentationAnimator = val8.GetComponent(); if ((Object)(object)artBundle != (Object)null) { eavesdropperAI.rustle = artBundle.LoadAsset("assets/eavesdropper/rustle.wav") ?? eavesdropperAI.rustle; eavesdropperAI.fixation = artBundle.LoadAsset("assets/eavesdropper/fixation.wav") ?? eavesdropperAI.fixation; eavesdropperAI.inhale = artBundle.LoadAsset("assets/eavesdropper/inhale.wav") ?? eavesdropperAI.inhale; eavesdropperAI.echoClick = artBundle.LoadAsset("assets/eavesdropper/echo-click.wav") ?? eavesdropperAI.echoClick; eavesdropperAI.echoPulse = artBundle.LoadAsset("assets/eavesdropper/echo-pulse.wav") ?? eavesdropperAI.echoPulse; } val.enemyPrefab = val2; return val; } private static GameObject? LoadArt(Transform parent) { string text = Path.Combine(Path.GetDirectoryName(typeof(Plugin).Assembly.Location), "eavesdropper.assets"); if (!File.Exists(text)) { return null; } artBundle = AssetBundle.LoadFromFile(text); if ((Object)(object)artBundle == (Object)null) { throw new InvalidDataException("Cannot load eavesdropper.assets. Build for Windows with matching Unity version."); } GameObject obj = artBundle.LoadAsset("assets/eavesdropper/eavesdroppervisual.prefab"); if ((Object)(object)obj == (Object)null) { throw new InvalidDataException("Art bundle is missing assets/eavesdropper/eavesdroppervisual.prefab."); } return Object.Instantiate(obj, parent, false); } internal static GameObject BuildVisual(Transform parent) { return CreatureRig.Build(parent); } private static AudioClip Synth(string name, float seconds, int kind) { AudioClip val = AudioClip.Create(name, (int)(seconds * 22050f), 1, 22050, false); float[] array = new float[val.samples]; Random random = new Random(718 + kind); float num = 0f; for (int i = 0; i < array.Length; i++) { float num2 = (float)i / 22050f; float num3 = (float)(random.NextDouble() * 2.0 - 1.0); num = num * 0.72f + num3 * 0.28f; float num4 = 0f; switch (kind) { case 4: num4 = 0.65f * Mathf.Sin(MathF.PI * num2 / seconds); break; case 3: num4 = 0.35f * Mathf.Sin(MathF.PI * num2 / seconds) * (0.5f + 0.5f * Mathf.Sin(num2 * 180f)); break; case 0: num4 = 0.07f * Mathf.Sin(MathF.PI * num2 / seconds); break; case 1: { float[] array2 = new float[3] { 0f, 0.22f, 0.44f }; foreach (float num5 in array2) { if (num2 >= num5 && num2 < num5 + 0.025f) { num4 += 0.8f * Mathf.Exp((0f - (num2 - num5)) * 160f); } } break; } default: num4 = 0.65f * Mathf.Sin(MathF.PI * num2 / seconds); break; } array[i] = ((kind == 4) ? (Mathf.Sin(MathF.PI * 2f * (900f * num2 - 550f * num2 * num2)) * 0.7f + num * 0.3f) : ((kind == 1 && num2 < 0.6f) ? num3 : num)) * num4; } val.SetData(array, 0); return val; } } internal static class RuntimeBootstrap { private static bool installed; private static bool quitting; internal static void Install() { if (!installed) { installed = true; SceneManager.sceneLoaded += SceneLoaded; Application.quitting += Quitting; EnsureRuntime("plugin startup"); } } private static void SceneLoaded(Scene scene, LoadSceneMode mode) { EnsureRuntime("scene loaded: " + ((Scene)(ref scene)).name); } private static void EnsureRuntime(string reason) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown if (quitting) { return; } SessionWire sessionWire = SessionWire.Current; if ((Object)(object)sessionWire == (Object)null) { GameObject val = new GameObject("Eavesdropper.Runtime") { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)val); sessionWire = val.AddComponent(); } else { if (!((Component)sessionWire).gameObject.activeSelf) { ((Component)sessionWire).gameObject.SetActive(true); } if (!((Behaviour)sessionWire).enabled) { ((Behaviour)sessionWire).enabled = true; } } Plugin.Instance.Log($"Runtime bootstrap ({reason}): active={((Behaviour)sessionWire).isActiveAndEnabled}."); } private static void Quitting() { quitting = true; SceneManager.sceneLoaded -= SceneLoaded; Application.quitting -= Quitting; } } public sealed class SessionWire : MonoBehaviour { private const string VoiceName = "jeepg.eavesdropper.voice.v2"; private const string StateName = "jeepg.eavesdropper.state.v6"; private const string DamageName = "jeepg.eavesdropper.damage.v2"; private const string AckName = "jeepg.eavesdropper.ack.v1"; private const string EchoAckName = "jeepg.eavesdropper.echoack.v1"; internal const int OwnNoiseId = 1974301; private static SessionWire? instance; private NetworkManager? manager; private bool registered; private float nextVoice; private float nextDebug; private readonly VoiceActivity voiceWindow = new VoiceActivity(); internal static bool Diagnostics; internal static string VoiceStatus = "Waiting for a session"; private uint voiceSequence; private bool loggedFirstFrame; private string lastNetworkStatus = ""; private float nextErrorLog; private readonly ReportGate gate = new ReportGate(); private readonly HuntReceipts receipts = new HuntReceipts(); private readonly PulseReceipts pulseReceipts = new PulseReceipts(); private readonly PulseReceipts attackReceipts = new PulseReceipts(); private readonly Dictionary localHunt = new Dictionary(); internal static SessionWire? Current => instance; internal static bool Valid(PlayerControllerB? p) { if ((Object)(object)p != (Object)null && p.isPlayerControlled && !p.isPlayerDead) { return p.isInsideFactory; } return false; } internal static PlayerControllerB? FindPlayer(ulong client) { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || (singleton.IsServer && !singleton.ConnectedClients.ContainsKey(client))) { return null; } if ((Object)(object)StartOfRound.Instance == (Object)null) { return null; } PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if (Valid(val) && val.actualClientId == client && ((NetworkBehaviour)val).OwnerClientId == client) { return val; } } return null; } private void Awake() { instance = this; Plugin.Instance.Log("Runtime Awake: input/network component created on " + ((Object)((Component)this).gameObject).name); } private void OnEnable() { Plugin.Instance.Log("Runtime enabled."); } private void OnDisable() { Plugin.Instance.Log($"Runtime disabled: activeSelf={((Component)this).gameObject.activeSelf}, enabled={((Behaviour)this).enabled}."); ConfigMenu.Close(); Detach(); } private void Update() { try { ConfigMenu.Tick(); RuntimeTick(); } catch (Exception ex) { if (Time.unscaledTime >= nextErrorLog) { nextErrorLog = Time.unscaledTime + 5f; Plugin.Instance.Error("Runtime update failed: " + ex); } } } private unsafe void RuntimeTick() { //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Expected O, but got Unknown //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Expected O, but got Unknown //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Expected O, but got Unknown //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Expected O, but got Unknown //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Expected O, but got Unknown //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03bb: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_03d5: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (!loggedFirstFrame) { loggedFirstFrame = true; Plugin.Instance.Log($"Runtime Update active. Keyboard present={Keyboard.current != null}; F8 enabled={Plugin.DebugSpawn.Value}."); } string text = (((Object)(object)singleton == (Object)null) ? "waiting for NetworkManager" : ((!singleton.IsListening) ? "waiting for a hosted/joined session" : ((singleton.CustomMessagingManager == null) ? "waiting for messaging" : "session available"))); if (text != lastNetworkStatus) { lastNetworkStatus = text; Plugin.Instance.Log("Runtime: " + text); } Keyboard current = Keyboard.current; if (current != null && ((ButtonControl)current.f8Key).wasPressedThisFrame && !ConfigMenu.Open) { TryDebugSpawn(singleton); } if (!ConfigMenu.Open) { Keyboard current2 = Keyboard.current; if (current2 != null && ((ButtonControl)current2.f7Key).wasPressedThisFrame) { Diagnostics = !Diagnostics; } } if ((Object)(object)manager != (Object)(object)singleton || (registered && ((Object)(object)singleton == (Object)null || !singleton.IsListening))) { Detach(); } if ((Object)(object)singleton == (Object)null || !singleton.IsListening || singleton.CustomMessagingManager == null) { return; } if (!registered) { manager = singleton; singleton.CustomMessagingManager.RegisterNamedMessageHandler("jeepg.eavesdropper.voice.v2", new HandleNamedMessageDelegate(ReceiveVoice)); singleton.CustomMessagingManager.RegisterNamedMessageHandler("jeepg.eavesdropper.state.v6", new HandleNamedMessageDelegate(ReceiveState)); singleton.CustomMessagingManager.RegisterNamedMessageHandler("jeepg.eavesdropper.damage.v2", new HandleNamedMessageDelegate(ReceiveDamage)); singleton.CustomMessagingManager.RegisterNamedMessageHandler("jeepg.eavesdropper.ack.v1", new HandleNamedMessageDelegate(ReceiveAck)); singleton.CustomMessagingManager.RegisterNamedMessageHandler("jeepg.eavesdropper.echoack.v1", new HandleNamedMessageDelegate(ReceiveEchoAck)); singleton.OnClientDisconnectCallback += Disconnected; registered = true; Plugin.Instance.Log("Network handlers ready. Runtime gameVersionNum=" + GameNetworkManager.Instance.gameVersionNum + "; Unity=" + Application.unityVersion); } if (singleton.IsServer) { GameSoundHooks.Tick(); } PlayerControllerB p = GameNetworkManager.Instance?.localPlayerController; DissonanceComms val = StartOfRound.Instance?.voiceChatModule; VoicePlayerState val2 = (((Object)(object)val == (Object)null) ? null : val.FindPlayer(val.LocalPlayerName)); bool flag = val2 != null && val2.IsSpeaking && !val.IsMuted; float num = ((flag && float.IsFinite(val2.Amplitude)) ? Mathf.Clamp01(val2.Amplitude) : 0f); voiceWindow.Sample(flag, num); VoiceStatus = string.Format("Dissonance={0} transmitting={1} raw={2:F4} peak={3:F4}\nFacility player={4} {5} F7 hides this display", (val2 != null) ? "ready" : "unavailable", flag, num, voiceWindow.Peak, Valid(p), singleton.IsServer ? "HOST" : "CLIENT: hearing/progress shown on host"); if (!(Time.unscaledTime >= nextVoice)) { return; } nextVoice = Time.unscaledTime + 0.2f; ushort amp = voiceWindow.ReportAndReset(); if (!Valid(p)) { return; } uint seq = ++voiceSequence; if (singleton.IsServer) { ApplyVoice(singleton.LocalClientId, seq, amp); return; } FastBufferWriter val3 = default(FastBufferWriter); ((FastBufferWriter)(ref val3))..ctor(6, (Allocator)2, -1); try { ((FastBufferWriter)(ref val3)).WriteValueSafe(ref seq, default(ForPrimitives)); ((FastBufferWriter)(ref val3)).WriteValueSafe(ref amp, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("jeepg.eavesdropper.voice.v2", 0uL, val3, (NetworkDelivery)1); } finally { ((IDisposable)(*(FastBufferWriter*)(&val3))/*cast due to .constrained prefix*/).Dispose(); } } private void TryDebugSpawn(NetworkManager? nm) { //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Expected O, but got Unknown //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) Plugin.Instance.Log("F8 received: checking spawn conditions."); if (!Plugin.DebugSpawn.Value) { SpawnBlocked("EnableF8Spawn is false. Set it to true and restart."); return; } if ((Object)(object)nm == (Object)null || !nm.IsListening) { SpawnBlocked("Host a game first."); return; } if (!nm.IsServer) { SpawnBlocked("Only the host can spawn the enemy."); return; } if (Time.unscaledTime < nextDebug) { SpawnBlocked("Wait three seconds between spawns."); return; } PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null) { SpawnBlocked("Local player is not ready."); return; } if (!val.isPlayerControlled || val.isPlayerDead) { SpawnBlocked("A living, controlled player is required."); return; } if (!val.isInsideFactory) { SpawnBlocked("Enter the facility first; this enemy spawns indoors."); return; } if ((Object)(object)RoundManager.Instance == (Object)null) { SpawnBlocked("RoundManager is not ready."); return; } if (EavesdropperAI.Live.Count >= 4) { SpawnBlocked("The test limit of four enemies has been reached."); return; } if ((Object)(object)Plugin.Enemy == (Object)null || (Object)(object)Plugin.Enemy.enemyPrefab == (Object)null) { SpawnBlocked("Enemy prefab was not registered; inspect startup errors."); return; } nextDebug = Time.unscaledTime + 3f; NavMeshPath val2 = new NavMeshPath(); GameObject[] array = GameObject.FindGameObjectsWithTag("AINode"); NavMeshHit val3 = default(NavMeshHit); NetworkObject val5 = default(NetworkObject); for (int i = 0; i < array.Length; i++) { Vector3 position = array[i].transform.position; float num = Vector3.Distance(((Component)val).transform.position, position); if (!(num < 8f) && !(num > 24f) && EavesdropperAI.Blocked(((Component)val).transform.position + Vector3.up, position + Vector3.up) && NavMesh.SamplePosition(position, ref val3, 1f, -1) && NavMesh.CalculatePath(((Component)val).transform.position, ((NavMeshHit)(ref val3)).position, -1, val2) && (int)val2.status == 0) { NetworkObjectReference val4 = RoundManager.Instance.SpawnEnemyGameObject(((NavMeshHit)(ref val3)).position, 0f, -1, Plugin.Enemy); if (((NetworkObjectReference)(ref val4)).TryGet(ref val5, (NetworkManager)null)) { Plugin.Instance.Log($"F8 spawned hidden Eavesdropper {val5.NetworkObjectId}, {num:F1}m away. F7 shows hearing diagnostics."); } else { SpawnBlocked("Spawn returned no network object; inspect Unity log."); } return; } } SpawnBlocked("No hidden reachable indoor node 8–24m away. Move deeper into the facility and retry."); } private static void SpawnBlocked(string reason) { Plugin.Instance.Log("F8 spawn blocked: " + reason); } private void ApplyVoice(ulong sender, uint seq, ushort amp) { PlayerControllerB val = FindPlayer(sender); if (!gate.Accept(sender, seq, Time.unscaledTime, (Object)(object)val != (Object)null, out var credit)) { return; } foreach (EavesdropperAI item in EavesdropperAI.Live) { item.Voice(val, amp, credit); } } private void ReceiveVoice(ulong sender, FastBufferReader reader) { //IL_0034: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)manager == (Object)null) && manager.IsServer && ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position == 6) { uint seq = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe(ref seq, default(ForPrimitives)); ushort amp = default(ushort); ((FastBufferReader)(ref reader)).ReadValueSafe(ref amp, default(ForPrimitives)); ApplyVoice(sender, seq, amp); } } internal static void Snapshot(EavesdropperAI e) { instance?.SendState(e, byte.MaxValue); } internal static void Signal(EavesdropperAI e, Cue cue) { instance?.SendState(e, (byte)cue); } private unsafe void SendState(EavesdropperAI e, byte cue) { //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0127: 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) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) if (!registered || (Object)(object)manager == (Object)null || !manager.IsServer || !((NetworkBehaviour)e).IsSpawned) { return; } uint num = ++e.SnapshotSequence; if (cue == 2) { attackReceipts.Begin(((NetworkBehaviour)e).NetworkObjectId, num, Time.time); attackReceipts.Ack(((NetworkBehaviour)e).NetworkObjectId, 0uL, num, Time.time); } if (cue == 3) { pulseReceipts.Begin(((NetworkBehaviour)e).NetworkObjectId, num, Time.time); pulseReceipts.Ack(((NetworkBehaviour)e).NetworkObjectId, 0uL, num, Time.time); } if (cue == 6 || cue == 2) { receipts.Begin(((NetworkBehaviour)e).NetworkObjectId, num); receipts.Acknowledge(((NetworkBehaviour)e).NetworkObjectId, 0uL, num); localHunt[((NetworkBehaviour)e).NetworkObjectId] = num; } if (cue != byte.MaxValue) { Presentation.Cue(e, (Cue)cue); } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(96, (Allocator)2, -1); try { ulong networkObjectId = ((NetworkBehaviour)e).NetworkObjectId; ((FastBufferWriter)(ref val)).WriteValueSafe(ref networkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref num, default(ForPrimitives)); Vector3 position = ((Component)e).transform.position; ((FastBufferWriter)(ref val)).WriteValueSafe(ref position); Quaternion rotation = ((Component)e).transform.rotation; ((FastBufferWriter)(ref val)).WriteValueSafe(ref rotation); byte displayState = (byte)e.DisplayState; ((FastBufferWriter)(ref val)).WriteValueSafe(ref displayState, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref e.DisplayTarget, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref e.DisplayHunt, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref e.DisplayWarning, default(ForPrimitives)); displayState = (byte)((e.DisplayRecovering ? 1u : 0u) | (uint)(e.DisplayCrawling ? 2 : 0) | (uint)(e.DisplayDoorLunge ? 4 : 0) | (uint)(e.DisplayDoorBash ? 8 : 0)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref displayState, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref cue, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref e.DisplayPhase, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref e.DisplayAgitation, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref e.MotionPhase, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref e.DisplaySpeed, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref e.EchoHeadYaw, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref e.DisplayDoorPhase, default(ForPrimitives)); foreach (ulong connectedClientsId in manager.ConnectedClientsIds) { if (connectedClientsId != 0L) { manager.CustomMessagingManager.SendNamedMessage("jeepg.eavesdropper.state.v6", connectedClientsId, val, (NetworkDelivery)3); } } } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static EavesdropperAI? FindEnemy(ulong id) { NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton != (Object)null) || singleton.SpawnManager == null || !singleton.SpawnManager.SpawnedObjects.TryGetValue(id, out var value)) { return null; } return ((Component)value).GetComponent(); } private unsafe void ReceiveState(ulong sender, FastBufferReader reader) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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) //IL_0051: 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_0076: 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) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: 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_0108: 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_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0228: 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_023e: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)manager == (Object)null || manager.IsServer || sender != 0L || ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position != 83) { return; } ulong num = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); uint num2 = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num2, default(ForPrimitives)); Vector3 val = default(Vector3); ((FastBufferReader)(ref reader)).ReadValueSafe(ref val); Quaternion val2 = default(Quaternion); ((FastBufferReader)(ref reader)).ReadValueSafe(ref val2); byte b = default(byte); ((FastBufferReader)(ref reader)).ReadValueSafe(ref b, default(ForPrimitives)); ulong displayTarget = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref displayTarget, default(ForPrimitives)); float displayHunt = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref displayHunt, default(ForPrimitives)); float displayWarning = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref displayWarning, default(ForPrimitives)); byte b2 = default(byte); ((FastBufferReader)(ref reader)).ReadValueSafe(ref b2, default(ForPrimitives)); byte b3 = default(byte); ((FastBufferReader)(ref reader)).ReadValueSafe(ref b3, default(ForPrimitives)); float displayPhase = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref displayPhase, default(ForPrimitives)); float displayAgitation = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref displayAgitation, default(ForPrimitives)); float motionPhase = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref motionPhase, default(ForPrimitives)); float displaySpeed = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref displaySpeed, default(ForPrimitives)); float echoHeadYaw = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref echoHeadYaw, default(ForPrimitives)); float displayDoorPhase = default(float); ((FastBufferReader)(ref reader)).ReadValueSafe(ref displayDoorPhase, default(ForPrimitives)); EavesdropperAI eavesdropperAI = FindEnemy(num); if ((Object)(object)eavesdropperAI == (Object)null || !EavesdropperAI.Finite(val) || b > 11 || (eavesdropperAI.ReceivedSnapshot && (int)(num2 - eavesdropperAI.LastSnapshot) <= 0)) { return; } eavesdropperAI.LastSnapshot = num2; eavesdropperAI.DisplayState = (Mode)b; eavesdropperAI.DisplayTarget = displayTarget; eavesdropperAI.DisplayHunt = displayHunt; eavesdropperAI.DisplayWarning = displayWarning; eavesdropperAI.DisplayRecovering = (b2 & 1) != 0; eavesdropperAI.DisplayDoorBash = (b2 & 8) != 0; eavesdropperAI.DisplayDoorPhase = displayDoorPhase; eavesdropperAI.DisplayCrawling = (b2 & 2) != 0; eavesdropperAI.DisplayDoorLunge = (b2 & 4) != 0; eavesdropperAI.DisplayPhase = displayPhase; eavesdropperAI.DisplayAgitation = displayAgitation; eavesdropperAI.MotionPhase = motionPhase; eavesdropperAI.DisplaySpeed = displaySpeed; eavesdropperAI.EchoHeadYaw = echoHeadYaw; eavesdropperAI.RemotePosition = val; eavesdropperAI.RemoteRotation = val2; if (!eavesdropperAI.ReceivedSnapshot) { ((Component)eavesdropperAI).transform.position = val; ((Component)eavesdropperAI).transform.rotation = val2; } eavesdropperAI.ReceivedSnapshot = true; if (b3 > 10) { return; } Presentation.Cue(eavesdropperAI, (Cue)b3); if (b3 == 3) { FastBufferWriter val3 = default(FastBufferWriter); ((FastBufferWriter)(ref val3))..ctor(12, (Allocator)2, -1); try { ((FastBufferWriter)(ref val3)).WriteValueSafe(ref num, default(ForPrimitives)); ((FastBufferWriter)(ref val3)).WriteValueSafe(ref num2, default(ForPrimitives)); manager.CustomMessagingManager.SendNamedMessage("jeepg.eavesdropper.echoack.v1", 0uL, val3, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val3))/*cast due to .constrained prefix*/).Dispose(); } } if (b3 != 6 && b3 != 2) { return; } localHunt[num] = num2; FastBufferWriter val4 = default(FastBufferWriter); ((FastBufferWriter)(ref val4))..ctor(12, (Allocator)2, -1); try { ((FastBufferWriter)(ref val4)).WriteValueSafe(ref num, default(ForPrimitives)); ((FastBufferWriter)(ref val4)).WriteValueSafe(ref num2, default(ForPrimitives)); manager.CustomMessagingManager.SendNamedMessage("jeepg.eavesdropper.ack.v1", 0uL, val4, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val4))/*cast due to .constrained prefix*/).Dispose(); } } private void ReceiveEchoAck(ulong sender, FastBufferReader reader) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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) if (!((Object)(object)manager == (Object)null) && manager.IsServer && ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position == 12 && !((Object)(object)FindPlayer(sender) == (Object)null)) { ulong enemy = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref enemy, default(ForPrimitives)); uint seq = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe(ref seq, default(ForPrimitives)); pulseReceipts.Ack(enemy, sender, seq, Time.time); } } internal static bool EchoReady(EavesdropperAI e) { if ((Object)(object)instance?.manager == (Object)null) { return false; } List list = new List(); foreach (ulong connectedClientsId in instance.manager.ConnectedClientsIds) { if ((Object)(object)FindPlayer(connectedClientsId) != (Object)null) { list.Add(connectedClientsId); } } return instance.pulseReceipts.Ready(((NetworkBehaviour)e).NetworkObjectId, list, Time.time, Plugin.Settings.EchoWarningSeconds); } internal static bool EchoWarned(EavesdropperAI e, ulong player) { if ((Object)(object)instance != (Object)null) { return instance.pulseReceipts.CanDetect(((NetworkBehaviour)e).NetworkObjectId, player, Time.time, Plugin.Settings.EchoWarningSeconds); } return false; } private void ReceiveAck(ulong sender, FastBufferReader reader) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0055: 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) if (!((Object)(object)manager == (Object)null) && manager.IsServer && ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position == 12 && !((Object)(object)FindPlayer(sender) == (Object)null)) { ulong enemy = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref enemy, default(ForPrimitives)); uint num = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); receipts.Acknowledge(enemy, sender, num); attackReceipts.Ack(enemy, sender, num, Time.time); } } internal static bool Damage(EavesdropperAI enemy, PlayerControllerB player, int damage) { if ((Object)(object)instance != (Object)null) { return instance.SendDamage(enemy, player, damage); } return false; } private unsafe bool SendDamage(EavesdropperAI enemy, PlayerControllerB player, int damage) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: 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) if ((Object)(object)manager == (Object)null || !manager.IsServer || !attackReceipts.CanDetect(((NetworkBehaviour)enemy).NetworkObjectId, player.actualClientId, Time.time, Plugin.Settings.AttackWarning) || !receipts.CanDamage(((NetworkBehaviour)enemy).NetworkObjectId, player.actualClientId, out var sequence)) { return false; } uint hit = ++enemy.HitSequence; if (player.actualClientId == 0L) { return ApplyDamage(enemy, sequence, hit, damage); } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(20, (Allocator)2, -1); try { ulong networkObjectId = ((NetworkBehaviour)enemy).NetworkObjectId; ((FastBufferWriter)(ref val)).WriteValueSafe(ref networkObjectId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref sequence, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref hit, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref damage, default(ForPrimitives)); manager.CustomMessagingManager.SendNamedMessage("jeepg.eavesdropper.damage.v2", player.actualClientId, val, (NetworkDelivery)3); return true; } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private void ReceiveDamage(ulong sender, FastBufferReader reader) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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) if (!((Object)(object)manager == (Object)null) && !manager.IsServer && sender == 0L && ((FastBufferReader)(ref reader)).Length - ((FastBufferReader)(ref reader)).Position == 20) { ulong id = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref id, default(ForPrimitives)); uint hunt = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe(ref hunt, default(ForPrimitives)); uint hit = default(uint); ((FastBufferReader)(ref reader)).ReadValueSafe(ref hit, default(ForPrimitives)); int damage = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref damage, default(ForPrimitives)); EavesdropperAI eavesdropperAI = FindEnemy(id); if ((Object)(object)eavesdropperAI != (Object)null) { ApplyDamage(eavesdropperAI, hunt, hit, damage); } } } private bool ApplyDamage(EavesdropperAI e, uint hunt, uint hit, int damage) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0099: Unknown result type (might be due to invalid IL or missing references) if (!localHunt.TryGetValue(((NetworkBehaviour)e).NetworkObjectId, out var value) || value != hunt || (int)(hit - e.LastDamage) <= 0 || damage < 1 || damage > 100) { return false; } e.LastDamage = hit; PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if (!Valid(val)) { return false; } if (EavesdropperAI.Blocked(((Component)e).transform.position + Vector3.up * 1.5f, ((Component)val).transform.position + Vector3.up)) { return false; } val.DamagePlayer(damage, true, true, (CauseOfDeath)6, 0, false, Vector3.zero); return true; } internal static void Forget(ulong enemy) { if (!((Object)(object)instance == (Object)null)) { instance.attackReceipts.Forget(enemy); instance.receipts.Forget(enemy); instance.pulseReceipts.Forget(enemy); instance.localHunt.Remove(enemy); } } private void Disconnected(ulong id) { gate.Remove(id); foreach (EavesdropperAI item in EavesdropperAI.Live) { item.VoiceReadings.Remove(id); item.ForgetSound(id); } receipts.Disconnect(id); pulseReceipts.Disconnect(id); attackReceipts.Disconnect(id); } private void Detach() { if ((Object)(object)manager != (Object)null) { manager.OnClientDisconnectCallback -= Disconnected; if (manager.CustomMessagingManager != null) { string[] array = new string[5] { "jeepg.eavesdropper.voice.v2", "jeepg.eavesdropper.state.v6", "jeepg.eavesdropper.damage.v2", "jeepg.eavesdropper.ack.v1", "jeepg.eavesdropper.echoack.v1" }; foreach (string text in array) { manager.CustomMessagingManager.UnregisterNamedMessageHandler(text); } } } GameSoundHooks.Clear(); gate.Clear(); receipts.Clear(); pulseReceipts.Clear(); attackReceipts.Clear(); localHunt.Clear(); registered = false; manager = null; voiceSequence = 0u; } private void OnDestroy() { Plugin.Instance.Log("Runtime destroyed; scene bootstrap will restore it if the game is continuing."); ConfigMenu.Close(); Detach(); if ((Object)(object)instance == (Object)(object)this) { instance = null; } } private void LateUpdate() { ConfigMenu.HoldInput(); } private void OnGUI() { Presentation.Diagnostics(); ConfigMenu.Draw(); } } } namespace Eavesdropper.Art { public sealed class Joint { public string Name = ""; public int Parent; public Vector3 Position; } public readonly struct Vertex { public readonly Vector3 Position; public readonly int Joint; public readonly int Material; public Vertex(Vector3 position, int joint, int material) { Position = position; Joint = joint; Material = material; } } public sealed class Creature { public readonly List Joints = new List(); public readonly List Vertices = new List(); public readonly List[] Triangles = new List[3] { new List(), new List(), new List() }; private Vector3[] worldPositions = Array.Empty(); private Quaternion[] worldRotations = Array.Empty(); public static readonly string[] Clips = new string[19] { "Listen", "Retreat", "Sprint", "DoorCrawl", "Warn", "DoorWarn", "DoorLunge", "Lunge", "Recover", "Stunned", "EchoWarn", "EchoWarnCompact", "Dormant", "Wake", "Fixated", "Repelled", "Rest", "Wander", "Investigate" }; public int Bone(string name) { return Joints.FindIndex((Joint j) => j.Name == name); } private int Add(string name, int parent, Vector3 position) { Joints.Add(new Joint { Name = name, Parent = parent, Position = position }); return Joints.Count - 1; } public Creature() { int num = Add("Pelvis", -1, new Vector3(0f, 1.15f, -0.45f)); int num2 = Add("Chest", num, new Vector3(0f, 1.95f, -0.06f)); int num3 = Add("Head", num2, new Vector3(0f, 1.87f, 0.48f)); Tube(num, new Vector3[4] { new Vector3(0f, 1.05f, -0.45f), new Vector3(0f, 1.35f, -0.38f), new Vector3(0f, 1.65f, -0.24f), new Vector3(0f, 1.97f, -0.06f) }, new float[4] { 0.22f, 0.18f, 0.25f, 0.37f }, 0.65f, 0); Ellipsoid(num2, new Vector3(0f, 2f, -0.05f), new Vector3(0.44f, 0.35f, 0.27f), 0); Ellipsoid(num, new Vector3(0f, 1.2f, -0.43f), new Vector3(0.29f, 0.21f, 0.23f), 0); Tube(num2, new Vector3[3] { new Vector3(0f, 1.98f, 0.07f), new Vector3(0f, 1.97f, 0.27f), new Vector3(0f, 1.87f, 0.48f) }, new float[3] { 0.2f, 0.16f, 0.145f }, 0.9f, 0); Ellipsoid(num3, new Vector3(0f, 1.86f, 0.54f), new Vector3(0.205f, 0.24f, 0.18f), 0); Ellipsoid(num3, new Vector3(0f, 1.75f, 0.69f), new Vector3(0.14f, 0.29f, 0.15f), 1); for (int i = -1; i <= 1; i += 2) { string text = ((i < 0) ? "L" : "R"); int bone = Add("Face" + text, num3, new Vector3((float)i * 0.095f, 1.93f, 0.68f)); Ellipsoid(bone, new Vector3((float)i * 0.11f, 1.76f, 0.73f), new Vector3(0.095f, 0.29f, 0.12f), 0); for (int j = 0; j < 7; j++) { Tube(bone, new Vector3[2] { new Vector3((float)i * 0.072f, 1.56f + (float)j * 0.055f, 0.82f), new Vector3((float)i * 0.012f, 1.57f + (float)j * 0.055f, 0.846f) }, new float[2] { 0.015f, 0.001f }, 1f, 2, 6); } int bone2 = Add("Ear" + text, num3, new Vector3((float)i * 0.19f, 1.99f, 0.5f)); Ellipsoid(bone2, new Vector3((float)i * 0.25f, 2.04f, 0.5f), new Vector3(0.11f, 0.24f, 0.045f), 0); int num4 = Add("Arm" + text, num2, new Vector3((float)i * 0.43f, 2.08f, 0.02f)); int num5 = Add("Forearm" + text, num4, new Vector3((float)i * 1.04f, 1.27f, 0.13f)); int num6 = Add("Hand" + text, num5, new Vector3((float)i * 1.1f, 0.28f, 0.76f)); Ellipsoid(num4, new Vector3((float)i * 0.49f, 2.08f, 0.02f), new Vector3(0.2f, 0.29f, 0.19f), 0); Limb(num4, Joints[num4].Position, Joints[num5].Position, 0.18f, 0.1f); Ellipsoid(num5, Joints[num5].Position, new Vector3(0.13f, 0.14f, 0.13f), 0); Limb(num5, Joints[num5].Position, Joints[num6].Position, 0.11f, 0.065f); Ellipsoid(num6, new Vector3((float)i * 1.1f, 0.25f, 0.83f), new Vector3(0.14f, 0.075f, 0.18f), 0); for (int k = 0; k < 4; k++) { float num7 = (float)i * (0.97f + (float)k * 0.083f); float num8 = 0.92f + ((k == 0) ? (-0.09f) : 0f); int num9 = Add("Finger" + text + k, num6, new Vector3(num7, 0.24f, num8)); int num10 = Add("Claw" + text + k, num9, new Vector3(num7 + (float)i * 0.03f, 0.1f, num8 + 0.25f)); Limb(num9, Joints[num9].Position, Joints[num10].Position, 0.033f, 0.021f); Tube(num10, new Vector3[2] { Joints[num10].Position, new Vector3(num7 + (float)i * 0.045f, 0.06f, num8 + 0.4f) }, new float[2] { 0.023f, 0.001f }, 1f, 2, 7); } int num11 = Add("Thigh" + text, num, new Vector3((float)i * 0.22f, 1.15f, -0.43f)); int num12 = Add("Shin" + text, num11, new Vector3((float)i * 0.49f, 0.63f, -0.07f)); int num13 = Add("Foot" + text, num12, new Vector3((float)i * 0.4f, 0.14f, -0.72f)); Limb(num11, Joints[num11].Position, Joints[num12].Position, 0.16f, 0.09f); Limb(num12, Joints[num12].Position, Joints[num13].Position, 0.09f, 0.05f); Ellipsoid(num13, new Vector3((float)i * 0.4f, 0.11f, -0.62f), new Vector3(0.095f, 0.075f, 0.2f), 0); for (int l = 0; l < 3; l++) { Tube(num13, new Vector3[2] { new Vector3((float)i * (0.34f + (float)l * 0.06f), 0.11f, -0.49f), new Vector3((float)i * (0.34f + (float)l * 0.06f), 0.055f, -0.29f) }, new float[2] { 0.026f, 0.002f }, 1f, 2, 6); } for (int m = 0; m < 6; m++) { float num14 = 1.54f + (float)m * 0.079f; float num15 = 0.2f + (float)m * 0.025f; Tube(num2, new Vector3[4] { new Vector3((float)i * 0.045f, num14, -0.29f), new Vector3((float)i * num15, num14 + 0.028f, -0.1f), new Vector3((float)i * num15 * 0.82f, num14 - 0.025f, 0.15f), new Vector3((float)i * 0.06f, num14 - 0.09f, 0.17f) }, new float[4] { 0.027f, 0.032f, 0.025f, 0.011f }, 1f, 0, 7); } } for (int n = 0; n < 9; n++) { Ellipsoid((n < 4) ? num : num2, new Vector3(0f, 1.22f + (float)n * 0.108f, -0.62f + (float)n * 0.035f), new Vector3(0.055f, 0.06f, 0.07f), 0, 8, 5); } } private void Limb(int bone, Vector3 a, Vector3 b, float thick, float thin) { Tube(bone, new Vector3[5] { a, Vector3.Lerp(a, b, 0.16f), Vector3.Lerp(a, b, 0.52f), Vector3.Lerp(a, b, 0.9f), b }, new float[5] { thick * 0.75f, thick, thick * 0.72f, thin, thin * 0.85f }, 0.85f, 0); Vector3 vector = new Vector3(0f, 0.012f, 0.035f); Tube(bone, new Vector3[3] { Vector3.Lerp(a, b, 0.08f) + vector, Vector3.Lerp(a, b, 0.5f) + vector, Vector3.Lerp(a, b, 0.95f) + vector }, new float[3] { thick * 0.22f, thin * 0.3f, 0.009f }, 1f, 0, 6); } private void Tri(int a, int b, int c, int material) { Triangles[material].Add(a); Triangles[material].Add(b); Triangles[material].Add(c); } private void Tube(int bone, Vector3[] points, float[] radii, float flatten, int material, int sides = 12) { int count = Vertices.Count; for (int i = 0; i < points.Length; i++) { Vector3 vector = Vector3.Normalize(points[Math.Min(points.Length - 1, i + 1)] - points[Math.Max(0, i - 1)]); Vector3 vector2 = vector; Vector3 vector3 = Vector3.Normalize(Vector3.Cross(vector2: (Math.Abs(vector2.Z) < 0.9f) ? Vector3.UnitZ : Vector3.UnitX, vector1: vector2)); Vector3 vector4 = Vector3.Cross(vector, vector3); for (int j = 0; j < sides; j++) { float x = (float)(j * 2) * MathF.PI / (float)sides; float num = 1f + 0.055f * MathF.Sin((float)(j * 7 + i * 3 + bone) * 2.7f); Vertices.Add(new Vertex(points[i] + radii[i] * num * (vector3 * MathF.Cos(x) + vector4 * MathF.Sin(x) * flatten), bone, material)); if (i > 0) { int a = count + (i - 1) * sides + j; int num2 = count + (i - 1) * sides + (j + 1) % sides; int c = count + i * sides + j; int b = count + i * sides + (j + 1) % sides; Tri(a, num2, c, material); Tri(num2, b, c, material); } } } int count2 = Vertices.Count; Vertices.Add(new Vertex(points[0], bone, material)); Vertices.Add(new Vertex(points[^1], bone, material)); for (int k = 0; k < sides; k++) { Tri(count2, count + (k + 1) % sides, count + k, material); int num3 = count + (points.Length - 1) * sides; Tri(count2 + 1, num3 + k, num3 + (k + 1) % sides, material); } } private void Ellipsoid(int bone, Vector3 center, Vector3 radii, int material, int sides = 14, int rings = 9) { Vector3[] array = new Vector3[rings + 1]; float[] array2 = new float[rings + 1]; for (int i = 0; i <= rings; i++) { float x = MathF.PI * (float)i / (float)rings; array[i] = center + new Vector3(0f, (0f - MathF.Cos(x)) * radii.Y, 0f); array2[i] = Math.Max(0.001f, MathF.Sin(x) * radii.X); } Tube(bone, array, array2, radii.Z / radii.X, material, sides); } public void Pose(string clip, float time, Vector3[] positions, Quaternion[] rotations, float agitation = 0f) { string text = clip; bool flag = clip == "Wander"; bool flag2 = clip == "Investigate"; if (flag || flag2) { clip = "Retreat"; } bool flag3 = clip == "Dormant" || clip == "Rest"; bool flag4 = clip == "Wake" || clip == "Rest"; bool flag5 = clip == "Repelled"; float num = ((clip == "Rest") ? Math.Min(1f, time / 1.2f) : (flag3 ? 1f : (flag4 ? Math.Max(0f, 1f - time / 1.2f) : 0f))); if (flag3 || flag4 || flag5) { clip = "DoorCrawl"; } bool flag6 = clip == "EchoWarn" || clip == "EchoWarnCompact"; bool flag7 = clip == "DoorWarn" || clip == "EchoWarnCompact" || flag3 || flag4 || flag5; if (flag7) { clip = "DoorCrawl"; } float num2 = MathF.Sin(time * ((clip == "Sprint") ? 13f : (flag ? 5.5f : ((float)(flag2 ? 6 : 7))))); for (int i = 0; i < Joints.Count; i++) { Joint joint = Joints[i]; positions[i] = joint.Position - ((joint.Parent < 0) ? Vector3.Zero : Joints[joint.Parent].Position); rotations[i] = Quaternion.Identity; string name = joint.Name; float num3 = ((!name.EndsWith("L")) ? 1 : (-1)); Vector3 vector = Vector3.Zero; if (name == "Pelvis") { float num4; switch (clip) { default: num4 = 0f; break; case "Warn": num4 = 0.12f; break; case "Stunned": num4 = 0.3f; break; case "DoorCrawl": case "DoorLunge": num4 = 0.2f; break; } float num5 = num4; positions[i] += new Vector3(0f, 0f - num5 + 0.025f * MathF.Sin(time * 2.1f), 0f); if (clip == "Sprint" || clip == "Retreat") { positions[i] += new Vector3(0f, 0.055f * MathF.Abs(num2), 0f); } if (clip == "Stunned") { vector.X = 35f; vector.Z = 8f; } if (clip == "DoorCrawl" || clip == "DoorLunge") { vector.X = 52f * (flag4 ? num : 1f); } positions[i].Y -= num * 0.22f; if (flag2) { positions[i].Y -= 0.08f; } if (flag4) { positions[i].Y += (1f - num) * 0.2f; } positions[i].X += agitation * 0.006f * MathF.Sin(time * 27f); } if (name == "Chest") { float x; switch (clip) { default: x = 3f * MathF.Sin(time * 2f); break; case "Stunned": x = 0f; break; case "Lunge": x = 28f; break; case "Warn": x = -12f; break; case "DoorCrawl": case "DoorLunge": x = -10f; break; } vector = new Vector3(x, 0f, 0f); } if (name == "Head") { vector = new Vector3((clip == "DoorCrawl") ? (-30) : ((clip == "Warn") ? (-18) : 0), (clip == "Listen") ? (12f * MathF.Sin(time * 0.8f)) : 0f, (clip == "Listen") ? 8 : 0); } if (name.StartsWith("Ear")) { vector.Z = num3 * (flag6 ? 55f : ((flag3 || flag5) ? (-35f) : (flag4 ? (-35f + Math.Min(1f, time / ((num3 < 0f) ? 0.55f : 1.1f)) * 43f) : (8f + (5f + agitation * 10f) * MathF.Sin(time * (3.4f + agitation * 5f) + num3 * 0.8f))))); } if (name.StartsWith("Ear") && text == "Rest") { vector.Z = num3 * (8f - 43f * Math.Clamp((time - 0.8f) / 0.4f, 0f, 1f)); } if (name == "Chest") { vector.X += agitation * (2f + 2f * MathF.Sin(time * (3f + agitation * 5f))); } if (name == "Head" && flag4) { vector.X = -30f * num; } if (name == "Head" && text == "Fixated") { vector = new Vector3(-12f, 0f, 8f); } if (name == "Head" && flag) { vector = new Vector3(-4f, 14f * MathF.Sin(time * 0.8f), 3f * MathF.Sin(time * 0.5f)); } if (name == "Head" && flag2) { vector = new Vector3(-12f, 5f * MathF.Sin(time * 0.65f), 4f); } if (name == "Chest" && flag2) { vector.X += 8f; } if (name.StartsWith("Ear") && flag2) { vector.Z = num3 * (28f + 4f * MathF.Sin(time * 2f + num3)); } if (name.StartsWith("Face")) { vector.Z = num3 * (flag6 ? 2f : ((clip == "Warn" || flag7) ? Math.Min(36f, time * 50f) : ((float)((clip == "Lunge" || clip == "DoorLunge") ? 42 : 2)))); } if (name.StartsWith("Face") && text == "Fixated") { vector.Z = num3 * (2f + ((time < 0.65f) ? (8f * MathF.Max(0f, MathF.Sin(time * 28f))) : 0f)); } if (name.StartsWith("Arm")) { if (clip == "DoorCrawl" || clip == "DoorLunge") { positions[i].X = num3 * 0.27f; } switch (clip) { case "DoorCrawl": vector = new Vector3(-45f + num2 * num3 * 9f, 0f, (0f - num3) * 30f); break; case "Sprint": case "Retreat": vector = new Vector3(num2 * num3 * (float)((clip == "Sprint") ? 27 : 15), 0f, num3 * 5f); break; case "Warn": vector = new Vector3(-18f, 0f, num3 * 18f); break; case "DoorLunge": case "Lunge": vector = new Vector3(-65f, num3 * 10f, (0f - num3) * 14f); break; case "Recover": vector = new Vector3(8f, 0f, (0f - num3) * 9f); break; } } if (name.StartsWith("Forearm")) { vector = new Vector3(clip switch { "Sprint" => Math.Max(0f, num2 * num3) * 25f, "Warn" => -23f, "DoorCrawl" => 15f, _ => 0f, }, 0f, (clip == "DoorCrawl") ? (num3 * 20f) : 0f); } if (name.StartsWith("Thigh")) { vector = new Vector3(clip switch { "Retreat" => (0f - num2) * num3 * 14f, "Sprint" => (0f - num2) * num3 * 26f, "DoorCrawl" => 40f, _ => 0f, }, 0f, 0f); } if (name.StartsWith("Shin")) { vector.X = ((clip == "DoorCrawl") ? (-55f) : ((clip == "Sprint") ? (num2 * num3 * 18f) : 0f)); } if (name.StartsWith("Finger") || name.StartsWith("Claw")) { float x2; switch (clip) { default: x2 = 4f * MathF.Sin(time * 2f + (float)i); break; case "Lunge": case "DoorLunge": x2 = -12f; break; case "Warn": x2 = -18f; break; } vector.X = x2; } if (name.StartsWith("Finger") || name.StartsWith("Claw")) { vector.X -= agitation * 12f; } rotations[i] = Quaternion.CreateFromYawPitchRoll(vector.Y * (MathF.PI / 180f), vector.X * (MathF.PI / 180f), vector.Z * (MathF.PI / 180f)); } for (int j = -1; j <= 1; j += 2) { string text2 = ((j < 0) ? "L" : "R"); float num6 = num2 * (float)j; bool flag8 = !flag7 && (clip == "Sprint" || clip == "Retreat" || clip == "DoorCrawl"); float num7; switch (clip) { default: num7 = 0.76f; break; case "Warn": num7 = 1.2f; break; case "DoorLunge": case "Lunge": num7 = 2.05f; break; } float num8 = num7; float num9 = clip switch { "Warn" => 0.62f, "Lunge" => 1.15f, "DoorLunge" => 0.8f, _ => 0.28f, }; bool flag9 = clip == "DoorCrawl" || clip == "DoorLunge"; float num10 = (flag9 ? 0.34f : ((clip == "Stunned") ? 0.72f : ((clip == "Warn") ? 1.22f : 1.1f))); if (flag2) { num10 = 1f; num8 += 0.15f; } if (num > 0f) { num10 = num10 * (1f - num) + 0.4f * num; num8 = num8 * (1f - num) + 0.36f * num; num9 = 0.32f; } if (flag5) { num10 = 0.4f; num9 = 0.75f; num8 = 0.3f; } if (flag8) { num8 += num6 * ((clip == "Sprint") ? 0.42f : 0.2f); num9 += Math.Max(0f, num6) * ((clip == "Sprint") ? 0.3f : 0.13f); } Solve("Arm" + text2, "Forearm" + text2, "Hand" + text2, new Vector3((float)j * num10, num9, num8), new Vector3(flag9 ? 0f : ((float)j * 0.15f), 0.1f, -1f), positions, rotations); float z = -0.72f + num * 0.35f + (flag8 ? ((0f - num6) * 0.23f) : 0f); float y = 0.14f + (flag8 ? (Math.Max(0f, 0f - num6) * 0.17f) : 0f); Solve("Thigh" + text2, "Shin" + text2, "Foot" + text2, new Vector3((float)j * ((clip == "DoorCrawl") ? 0.27f : 0.4f), y, z), Vector3.UnitZ, positions, rotations); } } private void World(Vector3[] positions, Quaternion[] rotations) { if (worldPositions.Length != Joints.Count) { worldPositions = new Vector3[Joints.Count]; worldRotations = new Quaternion[Joints.Count]; } for (int i = 0; i < Joints.Count; i++) { int parent = Joints[i].Parent; worldRotations[i] = ((parent < 0) ? rotations[i] : Quaternion.Normalize(worldRotations[parent] * rotations[i])); worldPositions[i] = ((parent < 0) ? positions[i] : (worldPositions[parent] + Vector3.Transform(positions[i], worldRotations[parent]))); } } private static Quaternion Between(Vector3 a, Vector3 b) { a = Vector3.Normalize(a); b = Vector3.Normalize(b); float num = Vector3.Dot(a, b); if (num < -0.9999f) { return Quaternion.CreateFromAxisAngle(Vector3.Normalize(Vector3.Cross(a, (Math.Abs(a.X) < 0.9f) ? Vector3.UnitX : Vector3.UnitY)), MathF.PI); } return Quaternion.Normalize(new Quaternion(Vector3.Cross(a, b), 1f + num)); } public Vector3 JointPosition(string name, Vector3[] positions, Quaternion[] rotations) { World(positions, rotations); return worldPositions[Bone(name)]; } public void RefitHand(string side, Vector3 goal, Vector3[] positions, Quaternion[] rotations) { Solve("Arm" + side, "Forearm" + side, "Hand" + side, goal, new Vector3(0f, 0.1f, -1f), positions, rotations); } private void Solve(string upperName, string lowerName, string endName, Vector3 goal, Vector3 pole, Vector3[] positions, Quaternion[] rotations) { World(positions, rotations); int num = Bone(upperName); int num2 = Bone(lowerName); int num3 = Bone(endName); int parent = Joints[num].Parent; Vector3 vector = worldPositions[num]; Vector3 a = Joints[num2].Position - Joints[num].Position; Vector3 a2 = Joints[num3].Position - Joints[num2].Position; float num4 = a.Length(); float num5 = a2.Length(); Vector3 value = goal - vector; float num6 = Math.Max(Math.Abs(num4 - num5) + 0.001f, Math.Min(num4 + num5 - 0.001f, value.Length())); Vector3 vector2 = Vector3.Normalize(value); goal = vector + vector2 * num6; Vector3 value2 = pole - vector2 * Vector3.Dot(pole, vector2); if (value2.LengthSquared() < 1E-05f) { value2 = Vector3.Cross(vector2, Vector3.UnitX); } value2 = Vector3.Normalize(value2); float num7 = (num4 * num4 - num5 * num5 + num6 * num6) / (2f * num6); Vector3 vector3 = vector + vector2 * num7 + value2 * MathF.Sqrt(Math.Max(0f, num4 * num4 - num7 * num7)); Quaternion quaternion = Between(a, vector3 - vector); Quaternion quaternion2 = Between(a2, goal - vector3); rotations[num] = Quaternion.Inverse(worldRotations[parent]) * quaternion; positions[num2] = Vector3.Transform(vector3 - vector, Quaternion.Inverse(quaternion)); rotations[num2] = Quaternion.Inverse(quaternion) * quaternion2; positions[num3] = Vector3.Transform(goal - vector3, Quaternion.Inverse(quaternion2)); rotations[num3] = Quaternion.Inverse(quaternion2); } } } namespace Eavesdropper.Core { public enum SoundKind { Crouch, Walk, Run, Voice, Ordinary } public sealed class AgitationMeter { private readonly Settings config; private readonly Queue<(float Time, float Gain)> gains = new Queue<(float, float)>(); private float recent; public float Value { get; private set; } public float RestSeconds { get; private set; } public AgitationMeter(Settings settings) { config = settings; Value = Math.Clamp(settings.AgitationInitial, 0f, settings.AgitationMaximum); } public void ResetRest() { RestSeconds = 0f; } public void Event(float amount) { if (float.IsFinite(amount)) { Value = Math.Clamp(Value + Math.Max(0f, amount), 0f, config.AgitationMaximum); } } public void Ordinary(float amount, float now) { while (gains.Count > 0 && now - gains.Peek().Time >= 1f) { recent -= gains.Dequeue().Gain; } if (float.IsFinite(amount)) { float num = Math.Min(Math.Max(0f, amount), Math.Max(0f, config.OrdinaryNoiseGainCapPerSecond - recent)); if (!(num <= 0f)) { recent += num; gains.Enqueue((now, num)); Event(num); } } } public void Tick(float dt, bool dormant) { Value = Math.Clamp(Value, 0f, config.AgitationMaximum); if (!dormant) { ResetRest(); return; } float restSeconds = RestSeconds; RestSeconds += Math.Max(0f, dt); float num = Math.Max(0f, RestSeconds - config.DormantDecayDelaySeconds) - Math.Max(0f, restSeconds - config.DormantDecayDelaySeconds); Value = Math.Max(0f, Value - num * config.DormantDecayPerSecond); } } public readonly struct EchoResult { public readonly bool Found; public readonly bool Confirmed; public readonly Point Position; public readonly ulong Player; public EchoResult(Point position, ulong player, bool confirmed) { Found = true; Position = position; Player = player; Confirmed = confirmed; } } public sealed class StationaryEvidence { private readonly Dictionary counts = new Dictionary(); private readonly HashSet seen = new HashSet(); public void Begin() { seen.Clear(); } public bool Observe(ulong id, bool clear, bool cluttered, bool moving, int required) { seen.Add(id); if (!clear) { counts.Remove(id); return false; } if (moving) { counts[id] = 0; return true; } if (cluttered) { counts.Remove(id); return false; } counts.TryGetValue(id, out var value); counts[id] = value + 1; return value + 1 >= required; } public void End() { foreach (ulong item in new List(counts.Keys)) { if (!seen.Contains(item)) { counts.Remove(item); } } } public void Clear() { counts.Clear(); seen.Clear(); } } public sealed class ActivationGate { private readonly Dictionary active = new Dictionary(); public bool Rising(ulong source, bool on) { active.TryGetValue(source, out var value); active[source] = on; if (on) { return !value; } return false; } public void Clear() { active.Clear(); } } public static class RoundLifetime { public static bool ShouldDespawn(bool server, bool spawned, bool shipLeaving, bool shipPhase, bool allDead) { if (server && spawned) { return shipLeaving || shipPhase || allDead; } return false; } } public enum Mode : byte { Dormant, Investigating, Listening, Fixated, Rushing, Searching, Attacking, Stunned, Retreating, Echolocating, Wandering, Returning } public enum Cue : byte { Rustle, Fixation, Attack, EchoWarning, EchoPulse, Wake, Pursuit, Repelled, WallImpact, EchoFirst, Breath } public readonly struct Point { public readonly float X; public readonly float Y; public readonly float Z; public Point(float x, float y, float z) { X = x; Y = y; Z = z; } public static float Distance(Point a, Point b) { return (float)Math.Sqrt((a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y) + (a.Z - b.Z) * (a.Z - b.Z)); } } public interface IWorld { Point Position { get; } bool Arrived { get; } bool PathFailed { get; } bool ValidPlayer(ulong id); bool Move(Point point, float speed); void Stop(); bool AttackOpportunity(Point aim); void Face(Point aim); bool Strike(Point aim, int damage); void Search(Point center, float speed); void Signal(Cue cue); bool TryRetreat(out Point destination); bool ContinueStraight(float speed); bool EchoReady(); EchoResult EchoTarget(); void EchoFirst(); void CancelEcho(); int Leap(Point aim, float distance); bool Rest(out Point destination); void LookAtEcho(Point position); } public sealed class Brain { public const ulong NoPlayer = ulong.MaxValue; public readonly Settings Config; private readonly IWorld world; private readonly AgitationMeter meter; private readonly Queue faint = new Queue(); private readonly Dictionary progress = new Dictionary(); private readonly Dictionary speechAt = new Dictionary(); private readonly List ids = new List(); private float nextBreath = 8f; private float now; private float entered; private float persistUntil; private float confirmedUntil; private float nextEcho; private float nextExplore; private float nextSwitch; private float suppressedUntil; private float retreatUntil; private float stunUntil; private float nextScare = -100f; private float confidence; private float leadStrength; private float wakeUntil; private float restRetry; private float firstPulseAt = -1f; private float leapRemaining; private float recoveryUntil; private bool struck; private bool leaping; private bool continuedStraight; private bool soundLeadPending; private bool soundLeadArrived; private Point soundLead; private int reliableSounds; private float lastReliable = -100f; private ulong reliableSource = ulong.MaxValue; public Mode State { get; private set; } public ulong Target { get; private set; } = ulong.MaxValue; public Point LastHeard { get; private set; } public Point AttackAim { get; private set; } public float Agitation => meter.Value; public float RestSeconds => meter.RestSeconds; public float Confidence => confidence; public bool SensorySuppressed => now < suppressedUntil; public int Tier { get { if (!(Agitation >= Config.AgitationEnragedThreshold)) { if (!(Agitation >= Config.AgitationAngryThreshold)) { return (Agitation >= Config.AgitationIrritatedThreshold) ? 1 : 0; } return 2; } return 3; } } private float Walk => Config.WalkSpeed * TierValue(Config.InvestigationStirredMultiplier, Config.InvestigationIrritatedMultiplier, Config.InvestigationAngryMultiplier, Config.InvestigationEnragedMultiplier); private float Rush => Config.RushSpeed * TierValue(Config.PursuitStirredMultiplier, Config.PursuitIrritatedMultiplier, Config.PursuitAngryMultiplier, Config.PursuitEnragedMultiplier); private float LeapScale => TierValue(Config.LeapStirredMultiplier, Config.LeapIrritatedMultiplier, Config.LeapAngryMultiplier, Config.LeapEnragedMultiplier); private float EchoInterval => TierValue(Config.EchoIntervalStirred, Config.EchoIntervalIrritated, Config.EchoIntervalAngry, Config.EchoIntervalEnraged); public float HuntRemaining => Math.Max(0f, persistUntil - now); public float StateSeconds => Math.Max(0f, now - entered); public float WarningRemaining { get { if (State != Mode.Echolocating) { if (State != Mode.Attacking || leaping || Recovering) { return 0f; } return Math.Max(0f, Config.AttackWarning - StateSeconds); } return Math.Max(0f, Config.EchoWarningSeconds - StateSeconds); } } public bool Recovering { get { if (State == Mode.Attacking) { return recoveryUntil > 0f; } return false; } } public bool Leaping { get { if (State == Mode.Attacking && leaping) { return !Recovering; } return false; } } public bool DoorLunge => Leaping; private float TierValue(float a, float b, float c, float d) { if (Tier != 3) { if (Tier != 2) { if (Tier != 1) { return a; } return b; } return c; } return d; } public Brain(Settings config, IWorld world) { Config = config; this.world = world; meter = new AgitationMeter(config); } public float Progress(ulong id) { if (!progress.TryGetValue(id, out var value)) { return 0f; } return value; } private void Set(Mode mode) { if (State != mode) { if (State == Mode.Echolocating) { world.CancelEcho(); firstPulseAt = -1f; } if (State == Mode.Dormant || mode == Mode.Dormant) { meter.ResetRest(); } State = mode; entered = now; } } private void Search() { world.Stop(); Set(Mode.Searching); nextExplore = now + 1f; } private void Investigate(Point point) { LastHeard = point; if (world.Move(point, Walk)) { Set(Mode.Investigating); } else { Search(); } } private void HeardLead(Point point) { soundLead = point; soundLeadPending = true; soundLeadArrived = false; } private bool NearSoundLead() { Point position = world.Position; float num = position.X - soundLead.X; float num2 = position.Z - soundLead.Z; if (num * num + num2 * num2 <= 1.5625f) { return Math.Abs(position.Y - soundLead.Y) <= 2.5f; } return false; } private void Wake(Point point) { point = new Point((float)Math.Round(point.X), point.Y, (float)Math.Round(point.Z)); LastHeard = point; persistUntil = now + Config.HuntPersistenceSeconds; confidence = 0.45f; HeardLead(point); world.Stop(); Set(Mode.Wandering); wakeUntil = now + 1.2f; nextExplore = wakeUntil; nextEcho = now + EchoInterval; world.LookAtEcho(point); world.Signal(Cue.Wake); } private void Fixate() { world.Stop(); world.Face(LastHeard); Set(Mode.Fixated); world.Signal(Cue.Fixation); progress.Clear(); speechAt.Clear(); } private bool CanSwitch(ulong player, Point point, float strength) { if (Target == player) { return true; } if (now < nextSwitch) { return false; } if (Target == ulong.MaxValue || now >= confirmedUntil) { return true; } if (!(Point.Distance(world.Position, point) < Point.Distance(world.Position, LastHeard) * 0.8f)) { return strength > leadStrength * 1.35f; } return true; } private void Pursue(ulong player, Point point, float strength, bool fromSound = false) { if (CanSwitch(player, point, strength)) { if (fromSound) { HeardLead(point); } if (Target != player) { nextSwitch = now + Config.TargetSwitchCooldownSeconds; } bool num = State != Mode.Rushing || Target != player; Target = player; LastHeard = point; leadStrength = strength; confidence = 1f; confirmedUntil = now + Config.FixationSeconds; persistUntil = now + Config.HuntPersistenceSeconds; continuedStraight = false; world.LookAtEcho(point); if (world.Move(point, Rush)) { Set(Mode.Rushing); } else { Search(); } if (num) { world.Signal(Cue.Pursuit); } } } public void Voice(ulong player, Point position, bool qualifying, float credit) { Sound(SoundKind.Voice, player, position, qualifying ? 1 : 0, credit, player); } public void Noise(Point position, float loudness) { Sound(SoundKind.Ordinary, ulong.MaxValue, position, loudness, 0.15f, ulong.MaxValue); } public void Sound(SoundKind kind, ulong source, Point point, float audibility, float duration, ulong player = ulong.MaxValue) { if (!float.IsFinite(audibility) || audibility <= 0f || (player != ulong.MaxValue && !world.ValidPlayer(player))) { return; } audibility = Math.Min(1f, audibility); bool flag = SensorySuppressed; if (!flag) { Mode state = State; bool flag2 = state - 6 <= Mode.Fixated; flag = flag2; } if (flag) { return; } float num; if (kind == SoundKind.Run) { num = Config.AgitationPerRunStep; } else { flag = (uint)kind <= 1u; num = (flag ? Config.AgitationPerWalkStep : (((kind == SoundKind.Voice) ? Config.AgitationPerVoiceSecond : Config.AgitationPerNoiseSecond) * Math.Max(0f, Math.Min(0.25f, duration)))); } float num2 = num; meter.Ordinary(num2 * audibility, now); if (State == Mode.Dormant) { meter.ResetRest(); while (faint.Count > 0 && now - faint.Peek() > Config.WakeFaintSoundWindowSeconds) { faint.Dequeue(); } faint.Enqueue(now); flag = (uint)(kind - 2) <= 1u; if ((flag && audibility >= 0.25f) || faint.Count >= Config.WakeFaintSoundCount) { faint.Clear(); Wake(point); } return; } persistUntil = now + Config.HuntPersistenceSeconds; if (now < wakeUntil) { return; } if (State == Mode.Fixated && kind == SoundKind.Voice) { Target = ulong.MaxValue; nextSwitch = 0f; Pursue(player, point, audibility, fromSound: true); return; } if (State == Mode.Rushing) { if (kind == SoundKind.Voice || kind == SoundKind.Run) { Pursue(player, point, audibility, fromSound: true); } else if (audibility >= Config.StrongNoise * (0.5f + (float)Tier / 6f) && now >= nextSwitch && (audibility > leadStrength * 1.35f || Point.Distance(world.Position, point) < Point.Distance(world.Position, LastHeard) * 0.8f)) { Target = ulong.MaxValue; confirmedUntil = 0f; nextSwitch = now + Math.Max(Config.TargetSwitchCooldownSeconds, Config.DistractionCooldown); confidence = 0.55f; HeardLead(point); Investigate(point); } return; } flag = Tier >= 2 && player != ulong.MaxValue && audibility >= 0.5f; if (flag) { bool flag2 = (uint)(kind - 2) <= 1u; flag = flag2; } if (flag) { Pursue(player, point, audibility, fromSound: true); return; } LastHeard = point; leadStrength = audibility; confidence = Math.Max(confidence, (audibility >= 0.25f) ? 0.6f : 0.3f); HeardLead(point); if (kind == SoundKind.Voice) { progress[player] = Progress(player) + Math.Max(0f, Math.Min(0.25f, duration)); speechAt[player] = now; if (Progress(player) + 0.0001f >= Config.SpeechSeconds) { Fixate(); return; } } if (kind != SoundKind.Voice && audibility >= 0.35f && State != Mode.Fixated) { reliableSounds = ((source != reliableSource || !(now - lastReliable <= 4f)) ? 1 : (reliableSounds + 1)); reliableSource = source; lastReliable = now; if (reliableSounds >= 3) { reliableSounds = 0; Fixate(); return; } } if (State == Mode.Fixated) { return; } if (audibility < 0.25f) { if (world.Move(point, Walk)) { Set(Mode.Wandering); nextExplore = now + Config.SearchSeconds; } else { Search(); } } else { Investigate(point); } } public void Irritation(float audibility, float duration) { meter.Ordinary(Config.AgitationPerNoiseSecond * Math.Max(0f, Math.Min(1f, audibility)) * Math.Max(0f, Math.Min(0.25f, duration)), now); } public bool Scare(Point source) { if (now < nextScare) { return false; } nextScare = now + Config.RepellentRetriggerCooldownSeconds; meter.Event(Config.AgitationPerScare); suppressedUntil = now + Config.SensoryDisruptionSeconds; float num = TierValue(Config.RepellentRetreatSeconds, Config.RepellentRetreatSeconds, (Config.RepellentRetreatSeconds + Config.RepellentRetreatSecondsEnraged) * 0.5f, Config.RepellentRetreatSecondsEnraged); retreatUntil = now + num; persistUntil = Math.Max(persistUntil, now + Config.HuntPersistenceSeconds); Target = ulong.MaxValue; confirmedUntil = 0f; LastHeard = source; world.Stop(); leaping = false; recoveryUntil = 0f; Set(Mode.Retreating); world.Signal(Cue.Repelled); if (world.TryRetreat(out var destination)) { world.Move(destination, Config.RetreatSpeed); } return true; } public void WallImpact() { if (Leaping) { meter.Event(Config.AgitationPerWallImpact); world.Stop(); leaping = false; stunUntil = now + Config.WallImpactStunSeconds; Set(Mode.Stunned); world.Signal(Cue.WallImpact); } } private void ReturnToRest() { Target = ulong.MaxValue; confirmedUntil = 0f; soundLeadPending = false; world.Stop(); Set(Mode.Returning); restRetry = now + Config.PathTimeout; if (world.Rest(out var destination)) { world.Move(destination, Walk); } } public void Tick(float dt, bool stunned) { if (!float.IsFinite(dt) || dt <= 0f) { return; } now += dt; meter.Tick(dt, State == Mode.Dormant && !stunned && now >= stunUntil); confidence = Math.Max(0f, confidence - dt * 0.025f); ids.Clear(); ids.AddRange(progress.Keys); foreach (ulong id in ids) { if (!world.ValidPlayer(id)) { progress.Remove(id); speechAt.Remove(id); } else if (now - speechAt[id] > 0.3f) { progress[id] = Math.Max(0f, progress[id] - Config.QuietDecay * dt); } } if (Target != ulong.MaxValue && !world.ValidPlayer(Target)) { Target = ulong.MaxValue; confirmedUntil = 0f; if (State == Mode.Rushing) { Search(); } } if (now >= confirmedUntil) { Target = ulong.MaxValue; } if (stunned || now < stunUntil) { world.Stop(); Set(Mode.Stunned); return; } if (State == Mode.Stunned) { Search(); return; } Mode state; if (now >= nextBreath) { state = State; if (state != Mode.Echolocating && state != Mode.Attacking) { nextBreath = now + TierValue(10f, 8f, 6f, 4f); world.Signal(Cue.Breath); } } if (State == Mode.Dormant) { return; } if (State == Mode.Retreating) { if (now >= retreatUntil) { Search(); } return; } if (State == Mode.Attacking) { AttackTick(dt); return; } if (HuntRemaining <= 0f && now >= confirmedUntil && State != Mode.Returning) { ReturnToRest(); } if (State == Mode.Returning) { if (world.Arrived || world.PathFailed || now >= restRetry) { world.Stop(); Set(Mode.Dormant); faint.Clear(); } return; } if (State == Mode.Echolocating) { if (firstPulseAt < 0f && StateSeconds >= Config.EchoWarningSeconds && world.EchoReady()) { world.EchoFirst(); firstPulseAt = now; world.Signal(Cue.EchoFirst); } else if (firstPulseAt >= 0f && now - firstPulseAt >= Config.EchoPulseSeparationSeconds) { EchoResult echoResult = world.EchoTarget(); nextEcho = now + EchoInterval; Search(); world.Signal(Cue.EchoPulse); if (echoResult.Confirmed) { meter.Event(Config.AgitationPerConfirmedScan); Pursue(echoResult.Player, echoResult.Position, 1f); } else if (echoResult.Found) { confidence = 0.5f; Investigate(echoResult.Position); } } return; } state = State; bool flag = ((state - 1 <= Mode.Investigating || state == Mode.Searching || state == Mode.Wandering) ? true : false); if (flag && soundLeadPending && (soundLeadArrived || world.Arrived) && !world.PathFailed && NearSoundLead() && now >= wakeUntil) { soundLeadArrived = true; if (Config.EcholocationEnabled && !SensorySuppressed) { world.Stop(); if (now >= nextEcho) { soundLeadPending = false; Set(Mode.Echolocating); firstPulseAt = -1f; world.Signal(Cue.EchoWarning); } return; } soundLeadPending = false; } if (State == Mode.Fixated) { if (StateSeconds >= Config.FixationSeconds) { Search(); } return; } if (State == Mode.Rushing) { if (Target != ulong.MaxValue && now < confirmedUntil && world.AttackOpportunity(LastHeard)) { AttackAim = LastHeard; world.Stop(); world.Face(AttackAim); Set(Mode.Attacking); struck = false; leaping = false; recoveryUntil = 0f; world.Signal(Cue.Attack); } else if (world.PathFailed) { Search(); } else if (world.Arrived) { if (!continuedStraight && world.ContinueStraight(Rush)) { continuedStraight = true; } else { Search(); } } return; } if (State == Mode.Investigating && (world.Arrived || world.PathFailed)) { if (world.PathFailed) { soundLeadPending = false; } Search(); return; } state = State; flag = ((state == Mode.Listening || state == Mode.Searching || state == Mode.Wandering) ? true : false); if (!flag || !(now >= nextExplore)) { return; } if (soundLeadPending) { if (world.Move(soundLead, Walk)) { Set(Mode.Investigating); } else { soundLeadPending = false; Search(); } nextExplore = now + Config.SearchSeconds; } else { world.Search(LastHeard, Walk); nextExplore = now + Config.SearchSeconds * (1f + (float)Tier * 0.15f); Set(Mode.Wandering); } } private void AttackTick(float dt) { if (Recovering) { if (now >= recoveryUntil) { Search(); } return; } if (!leaping) { if (StateSeconds < Config.AttackWarning) { return; } leaping = true; leapRemaining = Config.LungeSeconds * LeapScale; } float num = Math.Min(dt, leapRemaining); leapRemaining -= num; int num2 = world.Leap(AttackAim, Config.LungeSpeed * num); if (num2 < 0) { WallImpact(); return; } if (!struck && world.AttackOpportunity(AttackAim)) { struck = world.Strike(AttackAim, Config.Damage); } if (num2 > 0 || leapRemaining <= 1E-05f) { world.Stop(); leaping = false; recoveryUntil = now + Config.RecoverySeconds; } } } public static class ConfigInput { public static bool Parse(string text, Type type, out object value) { value = 0; if (type == typeof(bool) && bool.TryParse(text, out var result)) { value = result; return true; } if (type == typeof(int) && int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2)) { value = result2; return true; } if (type == typeof(float) && float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) && float.IsFinite(result3)) { value = result3; return true; } return false; } public static bool Tiers(float initial, float irritated, float angry, float enraged, float maximum) { if (float.IsFinite(maximum) && initial >= 0f && initial <= maximum && irritated > 0f && irritated < angry && angry < enraged) { return enraged < maximum; } return false; } } public sealed class PulseReceipts { private sealed class Pulse { public uint Sequence; public float Began; public readonly Dictionary Ack = new Dictionary(); } private readonly Dictionary pulses = new Dictionary(); public void Begin(ulong enemy, uint seq, float now) { pulses[enemy] = new Pulse { Sequence = seq, Began = now }; } public void Ack(ulong enemy, ulong client, uint seq, float now) { if (pulses.TryGetValue(enemy, out Pulse value) && value.Sequence == seq && !value.Ack.ContainsKey(client)) { value.Ack[client] = now; } } public bool Ready(ulong enemy, IEnumerable clients, float now, float warning) { if (!pulses.TryGetValue(enemy, out Pulse value) || now - value.Began < warning) { return false; } foreach (ulong client in clients) { if (!value.Ack.TryGetValue(client, out var value2) || now - value2 < warning) { return now - value.Began >= warning + 1f; } } return true; } public bool CanDetect(ulong enemy, ulong client, float now, float warning) { if (pulses.TryGetValue(enemy, out Pulse value) && value.Ack.TryGetValue(client, out var value2)) { return now - value2 >= warning; } return false; } public void Forget(ulong enemy) { pulses.Remove(enemy); } public void Disconnect(ulong client) { foreach (Pulse value in pulses.Values) { value.Ack.Remove(client); } } public void Clear() { pulses.Clear(); } } public sealed class HuntReceipts { private readonly Dictionary hunts = new Dictionary(); private readonly HashSet<(ulong Enemy, ulong Client)> receipts = new HashSet<(ulong, ulong)>(); public void Begin(ulong enemy, uint sequence) { Forget(enemy); hunts[enemy] = sequence; } public bool Acknowledge(ulong enemy, ulong client, uint sequence) { if (hunts.TryGetValue(enemy, out var value) && value == sequence) { return receipts.Add((enemy, client)); } return false; } public bool CanDamage(ulong enemy, ulong client, out uint sequence) { if (hunts.TryGetValue(enemy, out sequence)) { return receipts.Contains((enemy, client)); } return false; } public void Forget(ulong enemy) { hunts.Remove(enemy); receipts.RemoveWhere(((ulong Enemy, ulong Client) key) => key.Enemy == enemy); } public void Disconnect(ulong client) { receipts.RemoveWhere(((ulong Enemy, ulong Client) key) => key.Client == client); } public void Clear() { hunts.Clear(); receipts.Clear(); } } public static class LocalDetour { public static List? Find(IReadOnlyList nodes, Func clear, int budget = 512) { int count = nodes.Count; if (count < 2 || count > 100) { return null; } float[] array = new float[count]; int[] array2 = new int[count]; bool[] array3 = new bool[count]; for (int i = 0; i < count; i++) { array[i] = float.PositiveInfinity; array2[i] = -1; } array[0] = 0f; sbyte[,] array4 = new sbyte[count, count]; while (budget > 0) { int num = -1; float num2 = float.PositiveInfinity; for (int j = 0; j < count; j++) { if (!array3[j] && array[j] + Point.Distance(nodes[j], nodes[1]) < num2) { num = j; num2 = array[j] + Point.Distance(nodes[j], nodes[1]); } } if (num < 0) { return null; } if (num == 1) { List list = new List(); for (int num3 = 1; num3 >= 0; num3 = array2[num3]) { list.Add(nodes[num3]); } list.Reverse(); return list; } array3[num] = true; for (int k = 1; k < count; k++) { if (array3[k] || k == num) { continue; } float num4 = Point.Distance(nodes[num], nodes[k]); if ((num != 0 && k != 1 && num4 > 1.55f) || array[num] + num4 >= array[k]) { continue; } if (array4[num, k] == 0) { if (budget-- <= 0) { return null; } array4[num, k] = (array4[k, num] = (sbyte)(clear(nodes[num], nodes[k]) ? 1 : (-1))); } if (array4[num, k] >= 0) { array[k] = array[num] + num4; array2[k] = num; } } } return null; } } public static class NavigationPolicy { public static float SegmentDistance(Point p, Point a, Point b) { float num = b.X - a.X; float num2 = b.Z - a.Z; float num3 = num * num + num2 * num2; float num4 = ((num3 < 0.0001f) ? 0f : Math.Max(0f, Math.Min(1f, ((p.X - a.X) * num + (p.Z - a.Z) * num2) / num3))); return Point.Distance(new Point(p.X, 0f, p.Z), new Point(a.X + num4 * num, 0f, a.Z + num4 * num2)); } public static float RetreatScore(IReadOnlyList route, IReadOnlyList threats, bool cover) { if (route.Count < 2 || threats.Count == 0) { return float.NegativeInfinity; } float num = 0f; float num2 = float.MaxValue; float num3 = float.MaxValue; foreach (Point threat in threats) { float num4 = Point.Distance(route[0], threat); float num5 = Point.Distance(route[route.Count - 1], threat); num3 = Math.Min(num3, num4); num2 = Math.Min(num2, num5); if (num5 < num4 + 0.8f) { return float.NegativeInfinity; } for (int i = 1; i < route.Count; i++) { if (SegmentDistance(threat, route[i - 1], route[i]) < Math.Min(num4 - 0.2f, 3f)) { return float.NegativeInfinity; } } } for (int j = 1; j < route.Count; j++) { num += Point.Distance(route[j - 1], route[j]); } if (num > 40f || num2 < num3 + 2f) { return float.NegativeInfinity; } return Math.Min(num2, 12f) * 2f - Math.Max(0f, num2 - 14f) - num * 0.65f + (float)(cover ? 9 : 0); } } public sealed class FailedRoutes { private readonly List<(Point Position, float Until)> failed = new List<(Point, float)>(); public void Add(Point point, float now) { if (failed.Count == 12) { failed.RemoveAt(0); } failed.Add((point, now + 6f)); } public bool Contains(Point point, float now) { failed.RemoveAll(((Point Position, float Until) entry) => entry.Until <= now); foreach (var item in failed) { if (Point.Distance(item.Position, point) < 1.25f) { return true; } } return false; } } public sealed class ReportGate { private readonly Dictionary samples = new Dictionary(); public bool Accept(ulong sender, uint sequence, double now, bool validIdentity, out float credit) { credit = 0f; if (!validIdentity) { return false; } (double, uint) value; bool flag = samples.TryGetValue(sender, out value); if (flag && (now - value.Item1 < 0.15 || (int)(sequence - value.Item2) <= 0)) { return false; } credit = (flag ? ((float)Math.Min(0.2, now - value.Item1)) : 0.2f); samples[sender] = (now, sequence); return true; } public void Remove(ulong sender) { samples.Remove(sender); } public void Clear() { samples.Clear(); } } public sealed class Settings { public float SpeechSeconds = 6f; public float QuietDecay = 0.65f; public float VoiceThreshold = 0.025f; public float VoiceRange = 15f; public float NoiseRange = 15f; public float ObstructionMultiplier = 0.4f; public float NoiseThreshold = 0.15f; public float StrongNoise = 0.75f; public float FixationSeconds = 8f; public float FixationWarning = 1.5f; public float NoiseHuntSeconds = 8f; public float AttackWarning = 0.85f; public float LungeSeconds = 0.22f; public float RecoverySeconds = 1.6f; public float CompactPursuitSpeed = 6.5f; public float WalkSpeed = 2.7f; public float RushSpeed = 10.5f; public float LungeSpeed = 12f; public float AttackRange = 2.2f; public float SearchSeconds = 5f; public float DistractionCooldown = 5f; public float DistractionLock = 1.5f; public float PathTimeout = 10f; public float ListenSeconds = 8f; public int Damage = 60; public int LoudNoisesToHunt = 3; public float RetreatRange = 8f; public float RetreatSpeed = 3.8f; public float NoiseAgitationThreshold = 8f; public float AgitationDecay = 0.2f; public float VoiceSensitivity = 4f; public float DoorLungeSeconds = 0.4f; public float HallwayCommitDistance = 12f; public float EchoInterval = 8f; public float EchoWarningSeconds = 1.2f; public float EchoRange = 12f; public float EchoDoorMultiplier = 0.7f; public float EchoMotionThreshold = 0.12f; public float EchoHuntSeconds = 10f; public float CrouchFootstepRange = 3f; public float WalkFootstepRange = 7f; public float RunFootstepRange = 12f; public float ContinuousNoiseRange = 15f; public int WakeFaintSoundCount = 3; public int EchoStationaryConfirmations = 2; public float WakeFaintSoundWindowSeconds = 3f; public float HuntPersistenceSeconds = 90f; public float TargetSwitchCooldownSeconds = 1.5f; public bool EcholocationEnabled = true; public float EchoPulseSeparationSeconds = 0.4f; public float EchoMovementThreshold = 0.15f; public float EchoIntervalStirred = 9f; public float EchoIntervalIrritated = 7f; public float EchoIntervalAngry = 5f; public float EchoIntervalEnraged = 4f; public float AgitationInitial; public float AgitationMaximum = 1000f; public float AgitationIrritatedThreshold = 200f; public float AgitationAngryThreshold = 450f; public float AgitationEnragedThreshold = 750f; public float AgitationPerWalkStep = 2f; public float AgitationPerRunStep = 5f; public float AgitationPerVoiceSecond = 8f; public float AgitationPerNoiseSecond = 6f; public float AgitationPerConfirmedScan = 15f; public float AgitationPerWallImpact = 100f; public float AgitationPerScare = 80f; public float OrdinaryNoiseGainCapPerSecond = 25f; public float DormantDecayDelaySeconds = 35f; public float DormantDecayPerSecond = 5f; public bool HornRepels = true; public bool BlowdryerRepels = true; public bool DroppedBellRepels = true; public float RepellentRetreatSeconds = 4f; public float RepellentRetreatSecondsEnraged = 1.5f; public float SensoryDisruptionSeconds = 2.5f; public float RepellentRetriggerCooldownSeconds = 5f; public float WallImpactStunSeconds = 3f; public bool DebugBehaviorLogging; public bool DebugAgitationLogging; public bool DebugEchoVisualization; public float InvestigationStirredMultiplier = 1f; public float InvestigationIrritatedMultiplier = 1.15f; public float InvestigationAngryMultiplier = 1.3f; public float InvestigationEnragedMultiplier = 1.5f; public float PursuitStirredMultiplier = 1f; public float PursuitIrritatedMultiplier = 1.05f; public float PursuitAngryMultiplier = 1.15f; public float PursuitEnragedMultiplier = 1.3f; public float LeapStirredMultiplier = 1f; public float LeapIrritatedMultiplier = 1.1f; public float LeapAngryMultiplier = 1.4f; public float LeapEnragedMultiplier = 1.8f; } public sealed class SoundEventGate { private readonly Dictionary<(int, int, int, int), float> events = new Dictionary<(int, int, int, int), float>(); public bool Accept(int source, Point point, float now, float interval) { (int, int, int, int) key = (source, (int)Math.Round(point.X * 2f), (int)Math.Round(point.Y * 2f), (int)Math.Round(point.Z * 2f)); if (events.TryGetValue(key, out var value) && now - value < interval) { return false; } if (events.Count > 256) { foreach (var item in new List<(int, int, int, int)>(events.Keys)) { if (now - events[item] > 3f) { events.Remove(item); } } } events[key] = now; return true; } } public sealed class VoiceActivity { public float Peak { get; private set; } public void Sample(bool transmitting, float amplitude) { if (transmitting && float.IsFinite(amplitude)) { Peak = Math.Max(Peak, Math.Max(0f, Math.Min(1f, amplitude))); } } public ushort ReportAndReset() { ushort result = (ushort)Math.Round(Peak * 65535f); Peak = 0f; return result; } public static float Level(ushort report, float sensitivity) { return (float)(int)report / 65535f * sensitivity; } } }