Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of QuantumLocked v0.1.0
neogalt-br.QuantumLocked.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LethalCompanyInputUtils.Api; using LethalNetworkAPI; using LethalNetworkAPI.Utils; using Microsoft.CodeAnalysis; using QuantumLocked.Enemies; using QuantumLocked.Eyes; using QuantumLocked.Network; using QuantumLocked.Overlay; using Steamworks; using Steamworks.Data; using Unity.Netcode; using UnityEngine; using UnityEngine.Experimental.Rendering; using UnityEngine.InputSystem; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("neogalt-br.QuantumLocked")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+643040e13cb945a812feb6db93872a1642147b2e")] [assembly: AssemblyProduct("Quantum Locked")] [assembly: AssemblyTitle("neogalt-br.QuantumLocked")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.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 QuantumLocked { internal static class DebugLog { [Conditional("DEBUG")] public static void Info(string message) { QuantumLocked.Logger.LogInfo((object)("[debug] " + message)); } } [Serializable] internal sealed class GameplaySettings { public float BlinkLength; public float CalmIntervalMin; public float CalmIntervalMax; public float MaxInsanityIntervalMin; public float MaxInsanityIntervalMax; public float EyesShutInsanityDrain; public float CoilHeadBlinkSpeedMultiplier; public bool ReflexBlinksAtTerminal; [NonSerialized] private BlinkSettings? _blinkSettings; public BlinkSettings BlinkSettings { get { BlinkSettings blinkSettings = _blinkSettings; if (blinkSettings == null) { BlinkSettings obj = new BlinkSettings { BlinkLength = BlinkLength, CalmIntervalMin = CalmIntervalMin, CalmIntervalMax = CalmIntervalMax, MaxInsanityIntervalMin = MaxInsanityIntervalMin, MaxInsanityIntervalMax = MaxInsanityIntervalMax }; BlinkSettings blinkSettings2 = obj; _blinkSettings = obj; blinkSettings = blinkSettings2; } return blinkSettings; } } } internal sealed class LocalEyes : MonoBehaviour { private readonly EyesModel _eyes = new EyesModel(new Random().NextDouble); private EyelidOverlay? _overlay; private WorldBlur? _worldBlur; private void Start() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown RawImage playerScreenTexture = HUDManager.Instance.playerScreenTexture; RectTransform canvas = (RectTransform)((Component)((Graphic)playerScreenTexture).canvas.rootCanvas).transform; QuickMenuManager val = Object.FindObjectOfType<QuickMenuManager>(true); Transform keepVisible = (((Object)(object)val != (Object)null && (Object)(object)val.menuContainer != (Object)null) ? val.menuContainer.transform : null); _worldBlur = new WorldBlur(playerScreenTexture); _overlay = new EyelidOverlay(canvas, keepVisible); } private void OnDestroy() { _worldBlur?.Destroy(); _overlay?.Destroy(); } private void Update() { GameNetworkManager instance = GameNetworkManager.Instance; StartOfRound instance2 = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || _overlay == null || _worldBlur == null) { return; } PlayerControllerB localPlayerController = instance.localPlayerController; if ((Object)(object)localPlayerController == (Object)null) { return; } if (localPlayerController.isPlayerDead) { _eyes.Reset(); BlinkStates.SetLocal(localPlayerController, BlinkKind.None); _overlay.SetClosure(0f); _worldBlur.Set(0f, 0f, 0f); return; } QuantumLockedConfig configuration = QuantumLocked.Configuration; GameplaySettings current = EffectiveSettings.Current; bool isPlayerControlled = localPlayerController.isPlayerControlled; bool flag = !instance2.inShipPhase && instance2.shipDoorsEnabled && (!instance2.shipIsLeaving || !localPlayerController.isInElevator); bool flag2 = !localPlayerController.inTerminalMenu || current.ReflexBlinksAtTerminal; _eyes.Update(new EyesInput { DeltaTime = Time.deltaTime, Insanity = localPlayerController.insanityLevel, MaxInsanity = localPlayerController.maxInsanityLevel, ReflexBlinksAllowed = (isPlayerControlled && flag && flag2), Cosmetic = !(isPlayerControlled && flag), Settings = current.BlinkSettings, FadeProportion = configuration.FadeProportion.Value }); InputAction blinkKey = QuantumLocked.Inputs.BlinkKey; if (!localPlayerController.inTerminalMenu && !localPlayerController.isTypingChat && blinkKey.WasPressedThisFrame()) { _eyes.PressKey(); } if (blinkKey.WasReleasedThisFrame()) { _eyes.ReleaseKey(); } BlinkStates.SetLocal(localPlayerController, _eyes.SharedKind); _overlay.SetClosure(_eyes.Closure); _worldBlur.Set(_eyes.Blur, _eyes.Closure, configuration.BlurStrength.Value); } } [BepInPlugin("neogalt-br.QuantumLocked", "Quantum Locked", "0.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency("LethalNetworkAPI", "3.4.0")] public class QuantumLocked : BaseUnityPlugin { public static QuantumLocked Instance { get; private set; } internal static ManualLogSource Logger { get; private set; } internal static Harmony? Harmony { get; set; } internal static QuantumLockedConfig Configuration { get; private set; } internal static QuantumLockedInputs Inputs { get; private set; } private void Awake() { Logger = ((BaseUnityPlugin)this).Logger; Instance = this; Configuration = new QuantumLockedConfig(((BaseUnityPlugin)this).Config); Inputs = new QuantumLockedInputs(); EffectiveSettings.Init(Configuration); BlinkStates.Init(); Patch(); Logger.LogInfo((object)"neogalt-br.QuantumLocked v0.1.0 has loaded!"); } internal static void Patch() { //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_0017: Expected O, but got Unknown if (Harmony == null) { Harmony = new Harmony("neogalt-br.QuantumLocked"); } Logger.LogDebug((object)"Patching..."); Harmony.PatchAll(); Logger.LogDebug((object)"Finished patching!"); } internal static void Unpatch() { Logger.LogDebug((object)"Unpatching..."); Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } Logger.LogDebug((object)"Finished unpatching!"); } } internal sealed class QuantumLockedConfig { private const string Gameplay = "Gameplay"; private const string Visuals = "Visuals"; private readonly ConfigEntry<float> _blinkLength; private readonly ConfigEntry<float> _calmIntervalMin; private readonly ConfigEntry<float> _calmIntervalMax; private readonly ConfigEntry<float> _maxInsanityIntervalMin; private readonly ConfigEntry<float> _maxInsanityIntervalMax; private readonly ConfigEntry<float> _eyesShutInsanityDrain; private readonly ConfigEntry<float> _coilHeadBlinkSpeedMultiplier; private readonly ConfigEntry<bool> _reflexBlinksAtTerminal; public GameplaySettings LocalGameplay { get; private set; } public ConfigEntry<float> FadeProportion { get; } public ConfigEntry<float> BlurStrength { get; } public event Action? LocalGameplayChanged; public QuantumLockedConfig(ConfigFile file) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Expected O, but got Unknown //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Expected O, but got Unknown //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Expected O, but got Unknown //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Expected O, but got Unknown //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Expected O, but got Unknown BlinkSettings blinkSettings = new BlinkSettings(); _blinkLength = file.Bind<float>("Gameplay", "Blink length", blinkSettings.BlinkLength, new ConfigDescription("How long a Reflex Blink or a Manual Blink keeps the eyes closed, in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 5f), Array.Empty<object>())); _calmIntervalMin = file.Bind<float>("Gameplay", "Calm Blink Interval min", blinkSettings.CalmIntervalMin, new ConfigDescription("The shortest time between Reflex Blinks at zero Insanity, in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 120f), Array.Empty<object>())); _calmIntervalMax = file.Bind<float>("Gameplay", "Calm Blink Interval max", blinkSettings.CalmIntervalMax, new ConfigDescription("The longest time between Reflex Blinks at zero Insanity, in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 120f), Array.Empty<object>())); _maxInsanityIntervalMin = file.Bind<float>("Gameplay", "Maximum Insanity Blink Interval min", blinkSettings.MaxInsanityIntervalMin, new ConfigDescription("The shortest time between Reflex Blinks at maximum Insanity, in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 120f), Array.Empty<object>())); _maxInsanityIntervalMax = file.Bind<float>("Gameplay", "Maximum Insanity Blink Interval max", blinkSettings.MaxInsanityIntervalMax, new ConfigDescription("The longest time between Reflex Blinks at maximum Insanity, in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 120f), Array.Empty<object>())); _eyesShutInsanityDrain = file.Bind<float>("Gameplay", "Eyes Shut Insanity drain", 1f, new ConfigDescription("How much Insanity per second Eyes Shut removes, on top of the game's own change.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>())); _coilHeadBlinkSpeedMultiplier = file.Bind<float>("Gameplay", "Coil Head Blink speed multiplier", 1f, new ConfigDescription("Scales a Coil Head's speed while it moves only because everyone who could see it is Blinking.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); _reflexBlinksAtTerminal = file.Bind<bool>("Gameplay", "Reflex Blinks at the terminal", true, "Whether Reflex Blinks happen while using the terminal."); FadeProportion = file.Bind<float>("Visuals", "Eyelid fade proportion", 0.2f, new ConfigDescription("The share of the Blink length that closing, and separately opening, the eyelids takes.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.5f), Array.Empty<object>())); BlurStrength = file.Bind<float>("Visuals", "Blink blur strength", 0.7f, new ConfigDescription("How out of focus the world gets while the eyelids close and open, and as the eyes refocus. 0 turns the blur off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); file.SettingChanged += delegate(object _, SettingChangedEventArgs args) { if (!(args.ChangedSetting.Definition.Section != "Gameplay")) { LocalGameplay = ReadGameplaySettings(); this.LocalGameplayChanged?.Invoke(); } }; LocalGameplay = ReadGameplaySettings(); } private GameplaySettings ReadGameplaySettings() { return new GameplaySettings { BlinkLength = _blinkLength.Value, CalmIntervalMin = _calmIntervalMin.Value, CalmIntervalMax = _calmIntervalMax.Value, MaxInsanityIntervalMin = _maxInsanityIntervalMin.Value, MaxInsanityIntervalMax = _maxInsanityIntervalMax.Value, EyesShutInsanityDrain = _eyesShutInsanityDrain.Value, CoilHeadBlinkSpeedMultiplier = _coilHeadBlinkSpeedMultiplier.Value, ReflexBlinksAtTerminal = _reflexBlinksAtTerminal.Value }; } } public class QuantumLockedInputs : LcInputActions { [InputAction(/*Could not decode attribute arguments.*/)] public InputAction BlinkKey { get; set; } } public static class MyPluginInfo { public const string PLUGIN_GUID = "neogalt-br.QuantumLocked"; public const string PLUGIN_NAME = "Quantum Locked"; public const string PLUGIN_VERSION = "0.1.0"; } } namespace QuantumLocked.Patches { [HarmonyPatch(typeof(GameNetworkManager))] public class GameNetworkManagerPatch { private const char Separator = ','; [HarmonyPatch("SteamMatchmaking_OnLobbyCreated")] [HarmonyPostfix] private static void MarkLobbyAsQuantumLocked(Result result, ref Lobby lobby) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 if ((int)result == 1) { ((Lobby)(ref lobby)).SetData("neogalt-br.QuantumLocked", "0.1.0"); } } [HarmonyPatch("LobbyDataIsJoinable")] [HarmonyPostfix] private static void RefuseLobbiesWithoutQuantumLocked(ref Lobby lobby, ref bool __result) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (__result && string.IsNullOrEmpty(((Lobby)(ref lobby)).GetData("neogalt-br.QuantumLocked"))) { __result = false; Object.FindObjectOfType<MenuManager>().SetLoadingScreen(false, (RoomEnter)2, "The server host isn't running the Quantum Locked mod."); QuantumLocked.Logger.LogInfo((object)string.Format("Refused lobby {0}: its host isn't running {1}.", ((Lobby)(ref lobby)).Id, "Quantum Locked")); } } [HarmonyPatch("SetConnectionDataBeforeConnecting")] [HarmonyPostfix] private static void AnnounceQuantumLocked() { NetworkConfig networkConfig = NetworkManager.Singleton.NetworkConfig; string text = Encoding.ASCII.GetString(networkConfig.ConnectionData); networkConfig.ConnectionData = Encoding.ASCII.GetBytes(text + ",neogalt-br.QuantumLocked"); } [HarmonyPatch("ConnectionApproval")] [HarmonyPostfix] private static void RejectClientsWithoutQuantumLocked(ref ConnectionApprovalRequest request, ConnectionApprovalResponse response) { if (request.ClientNetworkId != NetworkManager.Singleton.LocalClientId && response.Approved) { string[] source = Encoding.ASCII.GetString(request.Payload).Split(','); if (!source.Contains("neogalt-br.QuantumLocked")) { response.Approved = false; response.Reason = "This lobby requires the Quantum Locked mod."; QuantumLocked.Logger.LogInfo((object)string.Format("Turned away client {0}: {1} isn't loaded.", request.ClientNetworkId, "Quantum Locked")); } } } } [HarmonyPatch(typeof(HUDManager))] public class HUDManagerPatch { [HarmonyPatch("Start")] [HarmonyPostfix] private static void AddLocalEyes(HUDManager __instance) { ((Component)__instance).gameObject.AddComponent<LocalEyes>(); } } [HarmonyPatch(typeof(PlayerControllerB))] public class PlayerControllerBInsanityPatch { [HarmonyPatch("SetPlayerSanityLevel")] [HarmonyPostfix] private static void DrainWhileEyesShut(PlayerControllerB __instance) { __instance.insanityLevel = InsanityDrain.Apply(BlinkStates.KindOf(__instance), __instance.insanityLevel, EffectiveSettings.Current.EyesShutInsanityDrain, Time.deltaTime); } } [HarmonyPatch(typeof(PlayerControllerB))] public class PlayerControllerBPatch { private const float NoLineOfSightAngle = -361f; private static bool _seeingThroughBlinks; internal static bool HasLineOfSightThroughBlinks(PlayerControllerB player, Vector3 position, float width) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) _seeingThroughBlinks = true; try { return player.HasLineOfSightToPosition(position, width, 60, -1f, -1); } finally { _seeingThroughBlinks = false; } } [HarmonyPatch("HasLineOfSightToPosition")] [HarmonyPostfix] private static void BlindWhileBlinking(PlayerControllerB __instance, ref bool __result) { if (__result && !_seeingThroughBlinks && BlinkStates.IsBlinking(__instance)) { __result = false; } } [HarmonyPatch("LineOfSightToPositionAngle")] [HarmonyPostfix] private static void BlindWhileBlinking(PlayerControllerB __instance, ref float __result) { if (__result != -361f && BlinkStates.IsBlinking(__instance)) { __result = -361f; } } } [HarmonyPatch(typeof(SpringManAI))] public class SpringManAIPatch { private const int ChasingState = 1; private const float LowPoint = 0.6f; private const float HighPoint = 3f; private const float ViewWidth = 68f; private const float MinimumEyeDistance = 0.3f; private static readonly FieldRef<SpringManAI, float> ChaseSpeed = AccessTools.FieldRefAccess<SpringManAI, float>("currentChaseSpeed"); private static readonly ConditionalWeakTable<SpringManAI, StrongBox<float>> VanillaChaseSpeeds = new ConditionalWeakTable<SpringManAI, StrongBox<float>>(); private static readonly List<PlayerSight> Sights = new List<PlayerSight>(); private const int VanillaPlayerSlots = 4; private static bool _gameChecksEverySlot; [HarmonyPatch("Update")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> CheckEveryPlayerSlot(IEnumerable<CodeInstruction> instructions) { //IL_0002: 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, (ILGenerator)null).MatchForward(false, (CodeMatch[])(object)new CodeMatch[2] { new CodeMatch((OpCode?)OpCodes.Ldc_I4_4, (object)null, (string)null), new CodeMatch((Func<CodeInstruction, bool>)((CodeInstruction instruction) => instruction.opcode == OpCodes.Blt || instruction.opcode == OpCodes.Blt_S), (string)null) }); _gameChecksEverySlot = val.IsValid; if (val.IsInvalid) { QuantumLocked.Logger.LogWarning((object)"Couldn't find the Coil Head's 4-player freeze check, so only the first 4 players can freeze a Coil Head or let it move on their Blinks. A game update may have changed it."); return val.InstructionEnumeration(); } return val.SetInstruction(CodeInstruction.Call((Expression<Action>)(() => PlayerSlots()))).InstructionEnumeration(); } private static int PlayerSlots() { return StartOfRound.Instance.allPlayerScripts.Length; } private static int SlotsTheGameChecks() { if (!_gameChecksEverySlot) { return Mathf.Min(4, PlayerSlots()); } return PlayerSlots(); } [HarmonyPatch("Update")] [HarmonyPrefix] private static void ScaleChaseSpeedForBlinks(SpringManAI __instance) { if (!((NetworkBehaviour)__instance).IsOwner || ((EnemyAI)__instance).isEnemyDead || ((EnemyAI)__instance).currentBehaviourStateIndex != 1 || __instance.onCooldownPhase > 0f) { if (VanillaChaseSpeeds.TryGetValue(__instance, out StrongBox<float> value)) { ChaseSpeed.Invoke(__instance) = value.Value; } return; } float value2 = VanillaChaseSpeeds.GetValue(__instance, (SpringManAI ai) => new StrongBox<float>(ChaseSpeed.Invoke(ai))).Value; float coilHeadBlinkSpeedMultiplier = EffectiveSettings.Current.CoilHeadBlinkSpeedMultiplier; if (coilHeadBlinkSpeedMultiplier == 1f) { ChaseSpeed.Invoke(__instance) = value2; return; } switch (CoilHeadRule.Decide(SightsOf(__instance))) { case CoilHeadMovement.BlinkMoving: ChaseSpeed.Invoke(__instance) = value2 * coilHeadBlinkSpeedMultiplier; break; case CoilHeadMovement.VanillaMoving: ChaseSpeed.Invoke(__instance) = value2; break; case CoilHeadMovement.Frozen: break; } } private static List<PlayerSight> SightsOf(SpringManAI coilHead) { //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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_0073: 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_009f: 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) Sights.Clear(); Vector3 position = ((Component)coilHead).transform.position; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; int num = SlotsTheGameChecks(); for (int i = 0; i < num; i++) { PlayerControllerB val = allPlayerScripts[i]; if (((EnemyAI)coilHead).PlayerIsTargetable(val, false, false, true)) { bool hasLineOfSight = (PlayerControllerBPatch.HasLineOfSightThroughBlinks(val, position + Vector3.up * 0.6f, 68f) || PlayerControllerBPatch.HasLineOfSightThroughBlinks(val, position + Vector3.up * 3f, 68f)) && coilHead.PlayerHasHorizontalLOS(val) && Vector3.Distance(((Component)val.gameplayCamera).transform.position, ((EnemyAI)coilHead).eye.position) > 0.3f; Sights.Add(new PlayerSight(hasLineOfSight, BlinkStates.IsBlinking(val))); } } return Sights; } } [HarmonyPatch(typeof(StartOfRound))] public class StartOfRoundPatch { [HarmonyPatch("OnPlayerDC")] [HarmonyPostfix] private static void ForgetDisconnectedPlayersBlink(int playerObjectNumber) { BlinkStates.Clear(playerObjectNumber); } } } namespace QuantumLocked.Overlay { internal sealed class BlurBand : MaskableGraphic { private const float BandHeight = 0.1f; private const int Segments = 32; private Texture? _texture; private Rect _uvRect = new Rect(0f, 0f, 1f, 1f); private float _closure; public bool Upper { get; set; } public override Texture mainTexture { get { if (!((Object)(object)_texture != (Object)null)) { return (Texture)(object)Graphic.s_WhiteTexture; } return _texture; } } public void Set(Texture texture, Rect uvRect, float closure, float alpha) { //IL_001c: 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_003b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_texture != (Object)(object)texture) { _texture = texture; ((Graphic)this).SetMaterialDirty(); } _uvRect = uvRect; _closure = closure; ((Graphic)this).color = new Color(1f, 1f, 1f, alpha); ((Graphic)this).SetVerticesDirty(); } protected override void OnPopulateMesh(VertexHelper vh) { //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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_0036: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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_00a6: Unknown result type (might be due to invalid IL or missing references) vh.Clear(); Rect rect = ((Graphic)this).rectTransform.rect; float num = EyelidShape.UpperLidBottom(_closure); Color32 vertexColor = Color32.op_Implicit(((Graphic)this).color); Color32 vertexColor2 = Color32.op_Implicit(new Color(((Graphic)this).color.r, ((Graphic)this).color.g, ((Graphic)this).color.b, 0f)); for (int i = 0; i <= 32; i++) { float u = (float)i / 32f; float num2 = num + EyelidShape.EdgeRise(u); AddVertex(vh, rect, u, num2 + 0.15f, vertexColor); AddVertex(vh, rect, u, num2, vertexColor); AddVertex(vh, rect, u, num2 - 0.1f, vertexColor2); if (i != 0) { int num3 = i * 3; int num4 = num3 - 3; for (int j = 0; j < 2; j++) { vh.AddTriangle(num4 + j, num3 + j, num3 + j + 1); vh.AddTriangle(num4 + j, num3 + j + 1, num4 + j + 1); } } } } private void AddVertex(VertexHelper vh, Rect rect, float u, float upperY, Color32 vertexColor) { //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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) float num = (Upper ? upperY : EyelidShape.MirrorToLowerLid(upperY)); Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(((Rect)(ref rect)).xMin + u * ((Rect)(ref rect)).width, ((Rect)(ref rect)).yMin + num * ((Rect)(ref rect)).height); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(((Rect)(ref _uvRect)).xMin + u * ((Rect)(ref _uvRect)).width, ((Rect)(ref _uvRect)).yMin + num * ((Rect)(ref _uvRect)).height); vh.AddVert(Vector2.op_Implicit(val), vertexColor, Vector4.op_Implicit(val2)); } } internal sealed class BlurCopy { private readonly int _width; private readonly List<RenderTexture> _steps = new List<RenderTexture>(); private RenderTexture? _smoothed; private int _sourceWidth; private int _sourceHeight; private GraphicsFormat _format; public RenderTexture Reduced => _steps[_steps.Count - 1]; public RenderTexture Smoothed => _smoothed; public BlurCopy(int width) { _width = width; } public void Make(Texture source) { EnsureTextures(source); Texture val = source; foreach (RenderTexture step in _steps) { Graphics.Blit(val, step); val = (Texture)(object)step; } Graphics.Blit(val, _smoothed); } public void Release() { foreach (RenderTexture step in _steps) { Release(step); } _steps.Clear(); Release(_smoothed); _smoothed = null; } private void EnsureTextures(Texture source) { //IL_000e: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) RenderTexture val = (RenderTexture)(object)((source is RenderTexture) ? source : null); GraphicsFormat val2 = (GraphicsFormat)((val == null) ? 4 : ((int)val.graphicsFormat)); if (!((Object)(object)_smoothed != (Object)null) || source.width != _sourceWidth || source.height != _sourceHeight || val2 != _format) { Release(); _sourceWidth = source.width; _sourceHeight = source.height; _format = val2; int num = source.width; int num2 = source.height; while (num / 2 >= _width) { num /= 2; num2 = Mathf.Max(1, num2 / 2); _steps.Add(CreateTexture(num, num2, val2)); } int num3 = Mathf.Max(1, Mathf.RoundToInt((float)_width * (float)source.height / (float)source.width)); if (num != _width || _steps.Count == 0) { _steps.Add(CreateTexture(_width, num3, val2)); } _smoothed = CreateTexture(_width * 2, num3 * 2, val2); } } private static RenderTexture CreateTexture(int width, int height, GraphicsFormat format) { //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_0009: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown RenderTexture val = new RenderTexture(width, height, 0, format) { filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1, hideFlags = (HideFlags)61 }; val.Create(); return val; } private static void Release(RenderTexture? texture) { if (!((Object)(object)texture == (Object)null)) { texture.Release(); Object.Destroy((Object)(object)texture); } } } internal sealed class EyelidOverlay { private const float BlackFrom = 0.85f; private readonly GameObject _root; private readonly RectTransform _upperLid; private readonly RectTransform _lowerLid; private readonly RawImage _vignette; private readonly RawImage _black; public EyelidOverlay(RectTransform canvas, Transform? keepVisible) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) RectTransform val = UiLayers.CreateFullScreenRect("QuantumLockedEyelids", canvas); _root = ((Component)val).gameObject; if ((Object)(object)keepVisible != (Object)null && keepVisible.IsChildOf((Transform)(object)canvas) && (Object)(object)keepVisible != (Object)(object)canvas) { Transform val2 = keepVisible; while ((Object)(object)val2.parent != (Object)(object)canvas) { val2 = val2.parent; } ((Transform)val).SetSiblingIndex(val2.GetSiblingIndex()); } _vignette = CreateLayer("Vignette", val, (Texture)(object)EyelidTextures.Vignette); _upperLid = ((Graphic)CreateLayer("UpperLid", val, (Texture)(object)EyelidTextures.Lid)).rectTransform; RawImage val3 = CreateLayer("LowerLid", val, (Texture)(object)EyelidTextures.Lid); val3.uvRect = new Rect(0f, 1f, 1f, -1f); _lowerLid = ((Graphic)val3).rectTransform; _black = CreateLayer("Black", val, (Texture)(object)Texture2D.whiteTexture); SetClosure(0f); } public void SetClosure(float closure) { //IL_003a: 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_0086: 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_00c5: 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) closure = Mathf.Clamp01(closure); _root.SetActive(closure > 0f); if (!(closure <= 0f)) { ((Graphic)_vignette).color = new Color(0f, 0f, 0f, closure); ((Graphic)_black).color = new Color(0f, 0f, 0f, Mathf.InverseLerp(0.85f, 1f, closure)); float num = EyelidShape.UpperLidBottom(closure); _upperLid.anchorMin = new Vector2(0f, num); _upperLid.anchorMax = new Vector2(1f, num + 1f); float num2 = EyelidShape.MirrorToLowerLid(num); _lowerLid.anchorMin = new Vector2(0f, num2 - 1f); _lowerLid.anchorMax = new Vector2(1f, num2); } } public void Destroy() { Object.Destroy((Object)(object)_root); } private static RawImage CreateLayer(string name, RectTransform parent, Texture texture) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) RawImage val = UiLayers.CreateGraphic<RawImage>(name, parent); ((Graphic)val).color = Color.black; val.texture = texture; return val; } } internal static class EyelidShape { public const float LidHeight = 1f; public const float LidArc = 0.3f; public const float LidSoftness = 0.15f; private const float LidTravel = 0.95000005f; public static float MirrorToLowerLid(float upperY) { return 1f - upperY; } public static float UpperLidBottom(float closure) { return 1f - Mathf.SmoothStep(0f, 1f, closure) * 0.95000005f; } public static float EdgeRise(float u) { float num = 2f * u - 1f; return 0.3f * (1f - num * num) * 1f; } } internal static class EyelidTextures { private static Texture2D? _lid; private static Texture2D? _vignette; public static Texture2D Lid => _lid ?? (_lid = CreateLid(256, 128)); public static Texture2D Vignette => _vignette ?? (_vignette = CreateVignette(256)); private static Texture2D CreateLid(int width, int height) { //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) Color32[] array = (Color32[])(object)new Color32[width * height]; for (int i = 0; i < height; i++) { float num = ((float)i + 0.5f) / (float)height; for (int j = 0; j < width; j++) { float u = ((float)j + 0.5f) / (float)width; float num2 = EyelidShape.EdgeRise(u) / 1f; float num3 = Mathf.SmoothStep(0f, 1f, (num - num2) / 0.15f); array[i * width + j] = new Color32((byte)0, (byte)0, (byte)0, (byte)Mathf.RoundToInt(num3 * 255f)); } } return CreateTexture(width, height, array); } private static Texture2D CreateVignette(int width) { //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) Color32[] array = (Color32[])(object)new Color32[width]; for (int i = 0; i < width; i++) { float num = Mathf.Abs(2f * ((float)i + 0.5f) / (float)width - 1f); float num2 = Mathf.SmoothStep(0f, 1f, num); array[i] = new Color32((byte)0, (byte)0, (byte)0, (byte)Mathf.RoundToInt(num2 * 255f)); } return CreateTexture(width, 1, array); } private static Texture2D CreateTexture(int width, int height, Color32[] pixels) { //IL_0004: 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_0010: 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_0020: Expected O, but got Unknown Texture2D val = new Texture2D(width, height, (TextureFormat)4, false) { wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1, hideFlags = (HideFlags)61 }; val.SetPixels32(pixels); val.Apply(false, true); return val; } } internal static class UiLayers { public static RectTransform CreateFullScreenRect(string name, RectTransform parent) { //IL_0014: 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_002b: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //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_0056: 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) GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) }) { layer = ((Component)parent).gameObject.layer }; RectTransform val2 = (RectTransform)val.transform; ((Transform)val2).SetParent((Transform)(object)parent, false); val2.anchorMin = Vector2.zero; val2.anchorMax = Vector2.one; val2.offsetMin = Vector2.zero; val2.offsetMax = Vector2.zero; ((Transform)val2).SetAsLastSibling(); return val2; } public static T CreateGraphic<T>(string name, RectTransform parent) where T : Graphic { T val = ((Component)CreateFullScreenRect(name, parent)).gameObject.AddComponent<T>(); ((Graphic)val).raycastTarget = false; return val; } } internal sealed class WorldBlur { private const int DefocusWidth = 108; private const int BandWidth = 54; private const float BandFadeIn = 0.25f; private readonly RawImage _gameView; private readonly GameObject _root; private readonly RawImage _defocus; private readonly BlurBand _upperBand; private readonly BlurBand _lowerBand; private readonly BlurCopy _defocusCopy = new BlurCopy(108); private readonly BlurCopy _bandCopy = new BlurCopy(54); public WorldBlur(RawImage gameView) { _gameView = gameView; RectTransform val = UiLayers.CreateFullScreenRect("QuantumLockedWorldBlur", ((Graphic)gameView).rectTransform); _root = ((Component)val).gameObject; _defocus = UiLayers.CreateGraphic<RawImage>("Defocus", val); _upperBand = UiLayers.CreateGraphic<BlurBand>("UpperBand", val); _upperBand.Upper = true; _lowerBand = UiLayers.CreateGraphic<BlurBand>("LowerBand", val); _root.SetActive(false); } public void Set(float blur, float closure, float strength) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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) //IL_00c5: 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) float num = strength * (1f - (1f - blur) * (1f - blur)); Texture texture = _gameView.texture; bool flag = num > 0f && closure < 1f && (Object)(object)texture != (Object)null; _root.SetActive(flag); if (flag) { Capture(texture); Rect uvRect = _gameView.uvRect; _defocus.texture = (Texture)(object)_defocusCopy.Smoothed; _defocus.uvRect = uvRect; ((Graphic)_defocus).color = new Color(1f, 1f, 1f, num); float alpha = num * Mathf.Clamp01(closure / 0.25f); _upperBand.Set((Texture)(object)_bandCopy.Smoothed, uvRect, closure, alpha); _lowerBand.Set((Texture)(object)_bandCopy.Smoothed, uvRect, closure, alpha); } } public void Destroy() { Object.Destroy((Object)(object)_root); _defocusCopy.Release(); _bandCopy.Release(); } private void Capture(Texture source) { //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_001b: Unknown result type (might be due to invalid IL or missing references) FilterMode filterMode = source.filterMode; source.filterMode = (FilterMode)1; _defocusCopy.Make(source); source.filterMode = filterMode; _bandCopy.Make((Texture)(object)_defocusCopy.Reduced); } } } namespace QuantumLocked.Network { internal static class BlinkStates { [Serializable] private struct Report { public int Player; public BlinkKind Kind; } private static LNetworkMessage<Report> _message = null; private static readonly Dictionary<int, BlinkKind> Kinds = new Dictionary<int, BlinkKind>(); private static BlinkKind _localKind; public static void Init() { _message = LNetworkMessage<Report>.Connect("BlinkState", (Action<Report, ulong>)Relay, (Action<Report>)Store, (Action<Report, ulong>)null); LNetworkUtils.OnNetworkStart += delegate { Kinds.Clear(); _localKind = BlinkKind.None; }; } public static bool IsBlinking(PlayerControllerB player) { return KindOf(player) != BlinkKind.None; } public static BlinkKind KindOf(PlayerControllerB player) { if (player.isPlayerDead || !Kinds.TryGetValue((int)player.playerClientId, out var value)) { return BlinkKind.None; } return value; } public static void SetLocal(PlayerControllerB local, BlinkKind kind) { if (kind == _localKind) { return; } _localKind = kind; Set((int)local.playerClientId, kind); if (LNetworkUtils.IsConnected) { Report report = new Report { Kind = kind }; if (LNetworkUtils.IsHostOrServer) { Relay(report, NetworkManager.Singleton.LocalClientId); } else { _message.SendServer(report); } } } public static void Clear(int player) { Kinds.Remove(player); } public static string DescribeBlinking() { if (Kinds.Count != 0) { return string.Join(", ", Kinds.Select((KeyValuePair<int, BlinkKind> entry) => $"player {entry.Key}: {entry.Value}")); } return "nobody"; } private static void Relay(Report report, ulong sender) { StartOfRound instance = StartOfRound.Instance; if (!((Object)(object)instance == (Object)null) && instance.ClientPlayerList.TryGetValue(sender, out var value)) { report.Player = value; _message.SendClients(report); } } private static void Store(Report report) { PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; if (!((Object)(object)localPlayerController != (Object)null) || report.Player != (int)localPlayerController.playerClientId) { Set(report.Player, report.Kind); } } private static void Set(int player, BlinkKind kind) { if (kind == BlinkKind.None) { Kinds.Remove(player); } else { Kinds[player] = kind; } } } internal static class EffectiveSettings { private static QuantumLockedConfig _config; private static LNetworkVariable<GameplaySettings?> _synced; private static GameplaySettings? _lastCurrent; public static GameplaySettings Current => (LNetworkUtils.IsConnected && !LNetworkUtils.IsHostOrServer && _synced.Value != null) ? _synced.Value : _config.LocalGameplay; public static void Init(QuantumLockedConfig config) { _config = config; _synced = LNetworkVariable<GameplaySettings>.Connect("HostSettings", (GameplaySettings)null, (LNetworkVariableWritePerms)0, (Action<GameplaySettings, GameplaySettings>)delegate { }); LNetworkUtils.OnNetworkStart += delegate { PublishIfHost(); }; config.LocalGameplayChanged += PublishIfHost; } private static void PublishIfHost() { if (LNetworkUtils.IsConnected && LNetworkUtils.IsHostOrServer) { _synced.Value = _config.LocalGameplay; } } [Conditional("DEBUG")] private static void LogIfChanged(GameplaySettings current) { if (current != _lastCurrent) { _lastCurrent = current; string text = ((current == _config.LocalGameplay) ? "this machine's own" : "the host's"); } } private static string Describe(GameplaySettings? settings) { if (settings != null) { return $"Blink length {settings.BlinkLength}, calm interval {settings.CalmIntervalMin}–{settings.CalmIntervalMax}, " + $"max-Insanity interval {settings.MaxInsanityIntervalMin}–{settings.MaxInsanityIntervalMax}, " + $"Eyes Shut drain {settings.EyesShutInsanityDrain}, Coil Head multiplier {settings.CoilHeadBlinkSpeedMultiplier}, " + $"Reflex Blinks at terminal {settings.ReflexBlinksAtTerminal}"; } return "none"; } } } namespace QuantumLocked.Eyes { public enum BlinkKind { None, Reflex, Manual, EyesShut } public sealed class BlinkSettings { public float BlinkLength { get; set; } = 0.3f; public float CalmIntervalMin { get; set; } = 8f; public float CalmIntervalMax { get; set; } = 14f; public float MaxInsanityIntervalMin { get; set; } = 2f; public float MaxInsanityIntervalMax { get; set; } = 4f; } public struct EyesInput { public float DeltaTime; public float Insanity; public float MaxInsanity; public bool ReflexBlinksAllowed; public bool Cosmetic; public BlinkSettings Settings; public float FadeProportion; } public sealed class EyesModel { private readonly Func<double> _random; private EyesInput _input = new EyesInput { Settings = new BlinkSettings() }; private double _now; private double _closedUntil; private double _openedAt; private bool _keyHeld; private bool _wasEligible; private bool _pendingPress; private double _pendingPressAt; private const float RefocusTime = 0.15f; private bool _wasOpeningOrOpen; private float _refocusFrom; private double _refocusStart; private double _refocusEnd; public bool IsClosed => Kind != BlinkKind.None; public BlinkKind Kind { get; private set; } public bool IsCosmetic { get { if (IsClosed) { return _input.Cosmetic; } return false; } } public BlinkKind SharedKind { get { if (!IsCosmetic) { return Kind; } return BlinkKind.None; } } public float BlinkTimer { get; private set; } public float Closure { get; private set; } public float Blur { get; private set; } private float FadeTime => Math.Min(0.5f, Math.Max(0f, _input.FadeProportion)) * _input.Settings.BlinkLength; public EyesModel(Func<double> random) { _random = random; } public void PressKey() { if (IsClosed) { _pendingPress = true; _pendingPressAt = _now; } else { StartManualBlink(); } } public void ReleaseKey() { if (_pendingPress) { _pendingPress = false; } else { if (!_keyHeld) { return; } _keyHeld = false; if (IsClosed) { _closedUntil = Math.Max(_closedUntil, _now + (double)(Closure * FadeTime)); if (_now >= _closedUntil) { Open(_now); } } } } public void Reset() { _keyHeld = false; _pendingPress = false; Kind = BlinkKind.None; Closure = 0f; Blur = 0f; _refocusFrom = 0f; _openedAt = _now; } public void Update(EyesInput input) { _input = input; float num = Math.Max(0f, input.DeltaTime); _now += num; if (_pendingPress && IsClosed && !_keyHeld) { double num2 = _closedUntil - (double)FadeTime; if (_pendingPressAt <= num2 && _now >= num2) { _pendingPress = false; _keyHeld = true; } } if (IsClosed && !_keyHeld && _now >= _closedUntil) { Open(_closedUntil); } if (!IsClosed && _pendingPress) { _pendingPress = false; StartManualBlink(); } if (!IsClosed && input.ReflexBlinksAllowed && _wasEligible) { BlinkTimer -= (float)Math.Min(num, _now - _openedAt); if (BlinkTimer <= 0f) { _closedUntil = _now + (double)BlinkTimer + (double)input.Settings.BlinkLength; Kind = BlinkKind.Reflex; } } if (input.ReflexBlinksAllowed && !_wasEligible) { RestartBlinkTimer(); } _wasEligible = input.ReflexBlinksAllowed; if (_keyHeld && IsClosed && _now >= _closedUntil) { Kind = BlinkKind.EyesShut; } float closure = Closure; UpdateClosure(num); UpdateBlur(closure); } private void StartManualBlink() { _keyHeld = true; _closedUntil = _now + (double)_input.Settings.BlinkLength; Kind = BlinkKind.Manual; } private void UpdateBlur(float previousClosure) { bool flag = Closure < previousClosure || (!IsClosed && Closure <= 0f); if (flag && !_wasOpeningOrOpen) { _refocusFrom = Blur; _refocusStart = _now; _refocusEnd = _now + (double)(Closure * FadeTime) + 0.15000000596046448; } _wasOpeningOrOpen = flag; float val = 0f; if (_refocusEnd > _refocusStart) { float num = Clamp01((float)((_refocusEnd - _now) / (_refocusEnd - _refocusStart))); val = _refocusFrom * num * num; } Blur = Math.Max(val, Closure); } private void UpdateClosure(float deltaTime) { float fadeTime = FadeTime; if (fadeTime <= 0f) { Closure = (IsClosed ? 1f : 0f); return; } float num = deltaTime / fadeTime; float val = 0f; if (IsClosed) { val = Closure + num; if (!_keyHeld) { val = Math.Min(val, (float)((_closedUntil - _now) / (double)fadeTime)); } } Closure = Clamp01(Math.Max(val, Closure - num)); } private void Open(double at) { Kind = BlinkKind.None; _openedAt = at; RestartBlinkTimer(); } private void RestartBlinkTimer() { BlinkSettings settings = _input.Settings; float t = ((_input.MaxInsanity > 0f) ? Clamp01(_input.Insanity / _input.MaxInsanity) : 0f); float num = Lerp(settings.CalmIntervalMin, settings.MaxInsanityIntervalMin, t); float to = Lerp(settings.CalmIntervalMax, settings.MaxInsanityIntervalMax, t); BlinkTimer = Lerp(num, to, (float)_random()); } private static float Lerp(float from, float to, float t) { return from + (to - from) * t; } private static float Clamp01(float value) { return Math.Min(1f, Math.Max(0f, value)); } } public static class InsanityDrain { public static float Apply(BlinkKind kind, float insanity, float drainPerSecond, float deltaTime) { if (kind != BlinkKind.EyesShut) { return insanity; } return Math.Max(0f, insanity - drainPerSecond * deltaTime); } } } namespace QuantumLocked.Enemies { public enum CoilHeadMovement { Frozen, BlinkMoving, VanillaMoving } public readonly struct PlayerSight { public bool HasLineOfSight { get; } public bool IsBlinking { get; } public PlayerSight(bool hasLineOfSight, bool isBlinking) { HasLineOfSight = hasLineOfSight; IsBlinking = isBlinking; } } public static class CoilHeadRule { public static CoilHeadMovement Decide(IReadOnlyList<PlayerSight> players) { bool flag = false; for (int i = 0; i < players.Count; i++) { PlayerSight playerSight = players[i]; if (playerSight.HasLineOfSight) { if (!playerSight.IsBlinking) { return CoilHeadMovement.Frozen; } flag = true; } } if (!flag) { return CoilHeadMovement.VanillaMoving; } return CoilHeadMovement.BlinkMoving; } } }