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 Terminal that can kill v1.0.9
plugins/Solon.TerminalThatCanKill.dll
Decompiled 16 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LethalDoors.Doors; using LethalDoors.Traps; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("")] [assembly: AssemblyCompany("Solon")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.9.0")] [assembly: AssemblyInformationalVersion("1.0.9+1735c2a96fa92bcc316f6a898981e973ef3ac9ff")] [assembly: AssemblyProduct("Terminal that can kill")] [assembly: AssemblyTitle("Solon.TerminalThatCanKill")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.9.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 LethalDoors { internal static class GameCompat { private const int TurretModeBerserk = 3; public static bool IsHost { get { if ((Object)(object)NetworkManager.Singleton != (Object)null) { if (!NetworkManager.Singleton.IsHost) { return NetworkManager.Singleton.IsServer; } return true; } return false; } } public static PlayerControllerB LocalPlayer { get { if (!((Object)(object)GameNetworkManager.Instance != (Object)null)) { return null; } return GameNetworkManager.Instance.localPlayerController; } } public static int LocalPlayerId { get { PlayerControllerB localPlayer = LocalPlayer; if (!((Object)(object)localPlayer != (Object)null)) { return -1; } return (int)localPlayer.playerClientId; } } public static bool IsPlayerAlive(PlayerControllerB p) { if ((Object)(object)p != (Object)null && p.isPlayerControlled) { return !p.isPlayerDead; } return false; } public static void KillLocalPlayer(PlayerControllerB player, int deathAnimation) { //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_0016: 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) try { player.KillPlayer(Vector3.up * 14f, true, (CauseOfDeath)17, deathAnimation, default(Vector3), false); } catch (Exception arg) { Plugin.Log.LogError((object)$"KillLocalPlayer failed: {arg}"); } } public static void KillEnemy(EnemyAI enemy) { try { enemy.KillEnemyOnOwnerClient(true); } catch (Exception) { try { enemy.KillEnemyServerRpc(true); } catch (Exception arg) { Plugin.Log.LogError((object)$"KillEnemy failed: {arg}"); } } } public static bool IsEnemyDead(EnemyAI enemy) { try { return (Object)(object)enemy == (Object)null || enemy.isEnemyDead; } catch { return (Object)(object)enemy == (Object)null; } } public static string EnemyName(EnemyAI enemy) { try { if ((Object)(object)enemy != (Object)null && (Object)(object)enemy.enemyType != (Object)null && !string.IsNullOrEmpty(enemy.enemyType.enemyName)) { return enemy.enemyType.enemyName; } } catch { } if (!((Object)(object)enemy != (Object)null)) { return "unknown"; } return ((object)enemy).GetType().Name; } public static void DetonateMine(Landmine mine) { if ((Object)(object)mine == (Object)null) { return; } try { if (!mine.hasExploded) { mine.ExplodeMineServerRpc(); } } catch (Exception arg) { Plugin.Log.LogError((object)$"DetonateMine failed: {arg}"); } } public static void BerserkTurret(Turret turret) { if ((Object)(object)turret == (Object)null) { return; } try { turret.turretActive = true; turret.SwitchTurretMode(3); turret.EnterBerserkModeServerRpc(LocalPlayerId); } catch (Exception arg) { Plugin.Log.LogError((object)$"BerserkTurret failed: {arg}"); } } public static void SustainBerserk(Turret turret, float minTimer) { if ((Object)(object)turret == (Object)null || !IsHost) { return; } try { turret.berserkTimer = Mathf.Max(turret.berserkTimer, minTimer); } catch { } } public static Vector3 DoorCenter(Component door) { //IL_0009: 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_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_0029: 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_0042: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)door == (Object)null) { return Vector3.zero; } try { Collider componentInChildren = door.GetComponentInChildren<Collider>(); if ((Object)(object)componentInChildren != (Object)null) { Bounds bounds = componentInChildren.bounds; return ((Bounds)(ref bounds)).center; } } catch { } return door.transform.position; } } public enum AffectedDoors { ShipDoor, TerminalDoors, Both } public enum DamageMode { InstantKill, DamageOverTime } internal sealed class ModConfig { public readonly ConfigEntry<bool> Enabled; public readonly ConfigEntry<bool> KillPlayers; public readonly ConfigEntry<bool> KillMonsters; public readonly ConfigEntry<AffectedDoors> AffectedDoors; public readonly ConfigEntry<float> SafeZoneSeconds; public readonly ConfigEntry<DamageMode> DamageMode; public readonly ConfigEntry<int> DamageAmount; public readonly ConfigEntry<float> ShipDoorCloseSeconds; public readonly ConfigEntry<float> TerminalDoorCloseSeconds; public readonly ConfigEntry<float> DoorwayThickness; public readonly ConfigEntry<float> DoorwayWidth; public readonly ConfigEntry<float> DoorwayHeight; public readonly ConfigEntry<int> PlayerDeathAnimationId; public readonly ConfigEntry<string> ExcludedEnemies; public readonly ConfigEntry<bool> EnableRemoteControl; public readonly ConfigEntry<float> MineErrorChance; public readonly ConfigEntry<float> TurretErrorChance; public readonly ConfigEntry<float> MineErrorDamageMultiplier; public readonly ConfigEntry<float> TurretRampageDuration; public readonly ConfigEntry<bool> TurretFlipOnBerserkExit; public readonly ConfigEntry<float> TurretFlipSmoothDuration; public readonly ConfigEntry<float> MineErrorChainRadius; public readonly ConfigEntry<bool> MineWarnBeforeDetonate; public ModConfig(ConfigFile cfg) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Expected O, but got Unknown //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Expected O, but got Unknown //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Expected O, but got Unknown //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Expected O, but got Unknown //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Expected O, but got Unknown //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Expected O, but got Unknown //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Expected O, but got Unknown //IL_0367: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Expected O, but got Unknown Enabled = cfg.Bind<bool>("Doors", "Enabled", true, "Master switch for the deadly-doors mechanic."); KillPlayers = cfg.Bind<bool>("Doors", "KillPlayers", true, "Kill players caught in a closing door's threshold."); KillMonsters = cfg.Bind<bool>("Doors", "KillMonsters", false, "Kill monsters caught in a closing door's threshold (only enemies that can enter the ship)."); AffectedDoors = cfg.Bind<AffectedDoors>("Doors", "AffectedDoors", LethalDoors.AffectedDoors.Both, "Which doors are deadly: ShipDoor, TerminalDoors or Both."); SafeZoneSeconds = cfg.Bind<float>("Doors", "SafeZoneSeconds", 5f, new ConfigDescription("Grace period after the ship lands during which doors do NOT kill. 0 disables the grace period.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), Array.Empty<object>())); DamageMode = cfg.Bind<DamageMode>("Doors", "DamageMode", LethalDoors.DamageMode.InstantKill, "InstantKill = kill immediately when the door finishes closing. DamageOverTime = damage players while the door stays shut on them."); DamageAmount = cfg.Bind<int>("Doors", "DamageAmount", 100, new ConfigDescription("Damage-per-second applied to players in DamageOverTime mode (ignored for InstantKill).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); ShipDoorCloseSeconds = cfg.Bind<float>("Doors.Advanced", "ShipDoorCloseSeconds", 1.6f, "Approximate duration of the ship-door close animation. The kill check fires this long after the door starts closing."); TerminalDoorCloseSeconds = cfg.Bind<float>("Doors.Advanced", "TerminalDoorCloseSeconds", 0.4f, "Delay (sec) between a facility door starting to close and the kill check firing. Big doors slam shut fast, so keep this small — larger values make the crush feel late and let quick open/close spam dodge it."); DoorwayThickness = cfg.Bind<float>("Doors.Advanced", "DoorwayThickness", 2f, new ConfigDescription("Depth (metres) of the kill slab THROUGH the doorway — the 'thin line'. A doorway is ~1.3m deep (you stand just inside/outside a closing door), so ~2.0 reliably catches someone in the opening while staying far tighter than a proximity sphere.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 6f), Array.Empty<object>())); DoorwayWidth = cfg.Bind<float>("Doors.Advanced", "DoorwayWidth", 3f, new ConfigDescription("Width (metres) of the kill slab across the doorway opening.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 8f), Array.Empty<object>())); DoorwayHeight = cfg.Bind<float>("Doors.Advanced", "DoorwayHeight", 5f, new ConfigDescription("Height (metres) of the kill slab. Kept generous so it never misses vertically.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 12f), Array.Empty<object>())); PlayerDeathAnimationId = cfg.Bind<int>("Doors.Advanced", "PlayerDeathAnimationId", 7, "Index into StartOfRound.playerRagdolls picking which corpse spawns. 7 = the Barber (ClaySurgeonAI) 'Snipping' death — body is launched up and ragdolls (default). 0 = plain physics ragdoll that just falls. -1 = no body."); ExcludedEnemies = cfg.Bind<string>("Doors.Advanced", "ExcludedEnemies", "Girl,RadMech,Manticoil,Docile,Roaming Locust,Red Locust Bees,Locust,Earth Leviathan,Forest Giant", "Comma-separated list of enemy internal names that can NEVER be crushed (matched case-insensitively as substrings). Defaults exclude enemies that cannot physically enter the ship (Ghost Girl, Old Bird, Manticoil, Locusts, etc.)."); EnableRemoteControl = cfg.Bind<bool>("RemoteControl", "EnableRemoteControl", true, "Replace terminal 'disable mine/turret' with detonate/rampage. False = vanilla behaviour (disable)."); MineErrorChance = cfg.Bind<float>("RemoteControl", "MineErrorChance", 0.15f, new ConfigDescription("Chance (0..1) that a remote MINE command critically malfunctions (chain detonation).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); TurretErrorChance = cfg.Bind<float>("RemoteControl", "TurretErrorChance", 0.15f, new ConfigDescription("Chance (0..1) that a remote TURRET command critically malfunctions (sustained rampage).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); MineErrorDamageMultiplier = cfg.Bind<float>("RemoteControl", "MineErrorDamageMultiplier", 2f, new ConfigDescription("On a mine error the blast is amplified: nearby mines within MineErrorChainRadius * this factor also detonate.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>())); TurretRampageDuration = cfg.Bind<float>("RemoteControl", "TurretRampageDuration", 5f, new ConfigDescription("Seconds a turret keeps re-triggering its berserk state on an error (chaotic spin-fire).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 30f), Array.Empty<object>())); TurretFlipOnBerserkExit = cfg.Bind<bool>("RemoteControl", "TurretFlipOnBerserkExit", true, "When a turret leaves berserk, turn its head 180° from the angle it had before berserk and keep it there as the new resting facing until the next berserk (it can still turn to fire at detected players)."); TurretFlipSmoothDuration = cfg.Bind<float>("RemoteControl", "TurretFlipSmoothDuration", 0.5f, new ConfigDescription("Seconds the 180° head turn takes on berserk exit. 0 = instant snap.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); MineErrorChainRadius = cfg.Bind<float>("RemoteControl.Advanced", "MineErrorChainRadius", 8f, "Base radius (metres) used to find neighbouring mines for the chain reaction on a mine error."); MineWarnBeforeDetonate = cfg.Bind<bool>("RemoteControl.Advanced", "MineWarnBeforeDetonate", false, "If true, a NORMAL (non-error) mine command plays the warning beep before exploding. Errors always detonate instantly."); } } [BepInPlugin("Solon.TerminalThatCanKill", "Terminal that can kill", "1.0.9")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "Solon.TerminalThatCanKill"; public const string PluginName = "Terminal that can kill"; public const string PluginVersion = "1.0.9"; private readonly Harmony _harmony = new Harmony("Solon.TerminalThatCanKill"); public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } internal static ModConfig Config { get; private set; } private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; Config = new ModConfig(((BaseUnityPlugin)this).Config); try { _harmony.PatchAll(typeof(Plugin).Assembly); Log.LogInfo((object)"Terminal that can kill v1.0.9 loaded — Harmony patches applied."); } catch (Exception arg) { Log.LogError((object)$"Failed to apply Harmony patches: {arg}"); } } } public static class MyPluginInfo { public const string PLUGIN_GUID = "Solon.TerminalThatCanKill"; public const string PLUGIN_NAME = "Terminal that can kill"; public const string PLUGIN_VERSION = "1.0.9"; } } namespace LethalDoors.Traps { internal static class RemoteControlManager { public static void HandleMine(Landmine mine) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mine == (Object)null) { return; } bool flag = Random.value < Plugin.Config.MineErrorChance.Value; if (!flag && Plugin.Config.MineWarnBeforeDetonate.Value) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(WarnThenDetonate(mine)); Plugin.Log.LogInfo((object)"Remote mine: armed (warning beep)."); return; } GameCompat.DetonateMine(mine); if (flag) { Plugin.Log.LogWarning((object)"Remote mine CRITICAL ERROR — chain detonation!"); ChainDetonateNearby(((Component)mine).transform.position); } else { Plugin.Log.LogInfo((object)"Remote mine: detonated."); } } private static IEnumerator WarnThenDetonate(Landmine mine) { yield return (object)new WaitForSeconds(0.85f); GameCompat.DetonateMine(mine); } private static void ChainDetonateNearby(Vector3 origin) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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) float num = Plugin.Config.MineErrorChainRadius.Value * Plugin.Config.MineErrorDamageMultiplier.Value; float num2 = num * num; Landmine[] array = Object.FindObjectsOfType<Landmine>(); foreach (Landmine val in array) { if (!((Object)(object)val == (Object)null)) { Vector3 val2 = ((Component)val).transform.position - origin; if (!(((Vector3)(ref val2)).sqrMagnitude > num2)) { ((MonoBehaviour)Plugin.Instance).StartCoroutine(DelayedDetonate(val, Random.Range(0.02f, 0.25f))); } } } } private static IEnumerator DelayedDetonate(Landmine mine, float delay) { yield return (object)new WaitForSeconds(delay); GameCompat.DetonateMine(mine); } public static void HandleTurret(Turret turret) { if (!((Object)(object)turret == (Object)null)) { bool num = Random.value < Plugin.Config.TurretErrorChance.Value; GameCompat.BerserkTurret(turret); if (num) { Plugin.Log.LogWarning((object)"Remote turret CRITICAL ERROR — sustained rampage!"); ((MonoBehaviour)Plugin.Instance).StartCoroutine(Rampage(turret, Plugin.Config.TurretRampageDuration.Value)); } else { Plugin.Log.LogInfo((object)"Remote turret: berserk."); } } } private static IEnumerator Rampage(Turret turret, float duration) { float end = Time.time + duration; while (Time.time < end && !((Object)(object)turret == (Object)null)) { GameCompat.SustainBerserk(turret, 3f); GameCompat.BerserkTurret(turret); yield return (object)new WaitForSeconds(1.5f); } } } } namespace LethalDoors.Patches { [HarmonyPatch(typeof(HangarShipDoor), "Update")] internal static class HangarShipDoorPatch { private const string ClosedStateName = "ShipDoorClose"; private static readonly Vector3 ShipDoorZoneCenter = new Vector3(-5.72f, 0.305f, -14.1f); private static float _closeTimer = -1f; private static bool _crushed; private static float _dotAccumulator; [HarmonyPostfix] private static void Postfix(HangarShipDoor __instance) { //IL_00a5: 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) if (!Plugin.Config.Enabled.Value || Plugin.Config.AffectedDoors.Value == AffectedDoors.TerminalDoors) { return; } if (!((Object)(object)StartOfRound.Instance != (Object)null) || !StartOfRound.Instance.shipHasLanded || !(__instance.doorPower < 1f)) { _closeTimer = -1f; _crushed = false; _dotAccumulator = 0f; return; } _closeTimer = ((_closeTimer < 0f) ? 0f : (_closeTimer + Time.deltaTime)); bool flag = false; Animator shipDoorsAnimator = __instance.shipDoorsAnimator; if ((Object)(object)shipDoorsAnimator != (Object)null) { AnimatorStateInfo currentAnimatorStateInfo = shipDoorsAnimator.GetCurrentAnimatorStateInfo(0); flag = ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).IsName("ShipDoorClose"); } if (flag || _closeTimer >= Plugin.Config.ShipDoorCloseSeconds.Value) { DoorZone zone = BuildShipZone(__instance); if (Plugin.Config.DamageMode.Value == DamageMode.DamageOverTime) { DoorCrushManager.ExecuteDamageTick(DoorKind.Ship, zone, ref _dotAccumulator); } else if (!_crushed) { _crushed = true; DoorCrushManager.ExecuteCrush(DoorKind.Ship, zone); } } } private static DoorZone BuildShipZone(HangarShipDoor door) { //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_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_0063: 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_0026: 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_002c: 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_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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) ModConfig config = Plugin.Config; Vector3 shipDoorZoneCenter = ShipDoorZoneCenter; Vector3 val = Vector3.forward; if ((Object)(object)door.outsideDoorPoint != (Object)null) { val = door.outsideDoorPoint.forward; Vector3 val2 = new Vector3(val.x, 0f, val.z); if (((Vector3)(ref val2)).sqrMagnitude < 0.01f) { val = door.outsideDoorPoint.position - shipDoorZoneCenter; } } return DoorZone.FromThroughAxis(shipDoorZoneCenter, val, config.DoorwayWidth.Value, config.DoorwayHeight.Value, config.DoorwayThickness.Value); } } [HarmonyPatch(typeof(StartOfRound))] internal static class StartOfRoundPatch { [HarmonyPatch("Start")] [HarmonyPostfix] private static void OnStart(StartOfRound __instance) { if ((Object)(object)LethalDoorsSession.Instance == (Object)null) { ((Component)__instance).gameObject.AddComponent<LethalDoorsSession>(); } TerminalDoorCrush.Clear(); TurretHeadFlipPatch.ClearStates(); } } [HarmonyPatch(typeof(TerminalAccessibleObject), "CallFunctionFromTerminal")] internal static class TerminalAccessibleObject_CallFunction_Patch { [HarmonyPrefix] private static bool Prefix(TerminalAccessibleObject __instance) { try { if (__instance.isBigDoor) { return true; } if (!Plugin.Config.EnableRemoteControl.Value) { return true; } Landmine val = ((Component)__instance).GetComponent<Landmine>() ?? ((Component)__instance).GetComponentInParent<Landmine>() ?? ((Component)__instance).GetComponentInChildren<Landmine>(); if ((Object)(object)val != (Object)null) { RemoteControlManager.HandleMine(val); return false; } Turret val2 = ((Component)__instance).GetComponent<Turret>() ?? ((Component)__instance).GetComponentInParent<Turret>() ?? ((Component)__instance).GetComponentInChildren<Turret>(); if ((Object)(object)val2 != (Object)null) { RemoteControlManager.HandleTurret(val2); return false; } } catch (Exception arg) { Plugin.Log.LogError((object)$"CallFunctionFromTerminal prefix error: {arg}"); } return true; } } [HarmonyPatch(typeof(TerminalAccessibleObject), "SetDoorOpen")] internal static class TerminalAccessibleObject_SetDoor_Patch { [HarmonyPrefix] private static void Prefix(TerminalAccessibleObject __instance, out bool __state) { __state = __instance.isDoorOpen; } [HarmonyPostfix] private static void Postfix(TerminalAccessibleObject __instance, bool open, bool __state) { if (__instance.isBigDoor && Plugin.Config.Enabled.Value && Plugin.Config.AffectedDoors.Value != AffectedDoors.ShipDoor && __state && !open) { TerminalDoorCrush.OnClosed(__instance); } } } [HarmonyPatch(typeof(Turret), "Update")] internal static class TurretHeadFlipPatch { private sealed class State { public Transform Head; public int PrevMode = -1; public float RememberedYaw; public bool HasResting; public float RestingYaw; public bool Animating; public float AnimTime; public float AnimDuration; public float AnimFromYaw; public float AnimToYaw; } private const int Berserk = 3; private const int Detection = 0; private static readonly Dictionary<Turret, State> _states = new Dictionary<Turret, State>(); public static void ClearStates() { _states.Clear(); } [HarmonyPostfix] private static void Postfix(Turret __instance) { if (!Plugin.Config.TurretFlipOnBerserkExit.Value) { return; } try { Process(__instance); } catch (Exception arg) { Plugin.Log.LogError((object)$"Turret head flip error: {arg}"); } } private static void Process(Turret turret) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected I4, but got Unknown //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected I4, but got Unknown //IL_0063: 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 (!_states.TryGetValue(turret, out var value)) { value = new State { Head = FindHead(turret), PrevMode = (int)turret.turretMode }; _states[turret] = value; } if ((Object)(object)value.Head == (Object)null) { return; } int num = (int)turret.turretMode; if (value.PrevMode != 3 && num == 3) { value.RememberedYaw = value.Head.localEulerAngles.y; value.Animating = false; } else if (value.PrevMode == 3 && num != 3) { value.RestingYaw = Normalize(value.RememberedYaw + 180f); value.HasResting = true; float value2 = Plugin.Config.TurretFlipSmoothDuration.Value; if (value2 > 0.01f) { value.Animating = true; value.AnimTime = 0f; value.AnimDuration = value2; value.AnimFromYaw = value.Head.localEulerAngles.y; value.AnimToYaw = value.RestingYaw; } else { value.Animating = false; SetYaw(value.Head, value.RestingYaw); } } value.PrevMode = num; if (num == 3) { return; } if (value.Animating) { value.AnimTime += Time.deltaTime; float num2 = Mathf.Clamp01(value.AnimTime / value.AnimDuration); SetYaw(value.Head, Mathf.LerpAngle(value.AnimFromYaw, value.AnimToYaw, num2)); if (num2 >= 1f) { value.Animating = false; } } else if (value.HasResting && num == 0) { SetYaw(value.Head, value.RestingYaw); } } private static void SetYaw(Transform head, float yaw) { //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_0008: 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_0015: Unknown result type (might be due to invalid IL or missing references) Vector3 localEulerAngles = head.localEulerAngles; head.localEulerAngles = new Vector3(localEulerAngles.x, yaw, localEulerAngles.z); } private static float Normalize(float angle) { return Mathf.Repeat(angle, 360f); } private static Transform FindHead(Turret turret) { if ((Object)(object)turret.turretRod != (Object)null) { return turret.turretRod; } Transform root = (((Object)(object)((Component)turret).transform.root != (Object)null) ? ((Component)turret).transform.root : ((Component)turret).transform); Transform val = DeepFind(root, "TurretHead") ?? DeepFind(root, "Gun"); if ((Object)(object)val != (Object)null) { return val; } Transform parent = ((Component)turret).transform.parent; if ((Object)(object)parent != (Object)null && parent.childCount > 1) { return parent.GetChild(1); } return ((Component)turret).transform; } private static Transform DeepFind(Transform root, string name) { if ((Object)(object)root == (Object)null) { return null; } Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { if (((Object)val).name == name) { return val; } } return null; } } } namespace LethalDoors.Doors { public enum DoorKind { Ship, Terminal } internal static class DoorCrushManager { public static void ExecuteCrush(DoorKind kind, DoorZone zone) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: 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) //IL_00ab: 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_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: 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) ModConfig config = Plugin.Config; if (!config.Enabled.Value || !AppliesTo(kind) || ((Object)(object)LethalDoorsSession.Instance != (Object)null && LethalDoorsSession.Instance.InSafePeriod)) { return; } if (config.KillPlayers.Value) { PlayerControllerB localPlayer = GameCompat.LocalPlayer; if (GameCompat.IsPlayerAlive(localPlayer)) { if (zone.Contains(((Component)localPlayer).transform.position)) { GameCompat.KillLocalPlayer(localPlayer, config.PlayerDeathAnimationId.Value); Plugin.Log.LogInfo((object)$"{kind} door crushed local player."); } else { Vector3 val = zone.ToLocal(((Component)localPlayer).transform.position); Plugin.Log.LogInfo((object)($"{kind} door closed: local player not in doorway. " + $"Offset from zone (width={val.x:F2}, height={val.y:F2}, through={val.z:F2}); " + $"half-extents={zone.HalfExtents}.")); } } } if (!config.KillMonsters.Value || !GameCompat.IsHost || !((Object)(object)RoundManager.Instance != (Object)null)) { return; } List<EnemyAI> spawnedEnemies = RoundManager.Instance.SpawnedEnemies; for (int i = 0; i < spawnedEnemies.Count; i++) { EnemyAI val2 = spawnedEnemies[i]; if (!((Object)(object)val2 == (Object)null) && EnemyWhitelist.CanBeCrushed(val2) && zone.Contains(((Component)val2).transform.position)) { GameCompat.KillEnemy(val2); Plugin.Log.LogInfo((object)$"{kind} door crushed enemy '{GameCompat.EnemyName(val2)}'."); } } } public static void ExecuteDamageTick(DoorKind kind, DoorZone zone, ref float accumulator) { //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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) ModConfig config = Plugin.Config; if (!config.Enabled.Value || !config.KillPlayers.Value || !AppliesTo(kind) || ((Object)(object)LethalDoorsSession.Instance != (Object)null && LethalDoorsSession.Instance.InSafePeriod)) { return; } PlayerControllerB localPlayer = GameCompat.LocalPlayer; if (!GameCompat.IsPlayerAlive(localPlayer)) { return; } if (!zone.Contains(((Component)localPlayer).transform.position)) { accumulator = 0f; return; } accumulator += (float)config.DamageAmount.Value * Time.deltaTime; if (accumulator < 1f) { return; } int num = Mathf.FloorToInt(accumulator); accumulator -= num; try { localPlayer.DamagePlayer(num, true, true, (CauseOfDeath)17, config.PlayerDeathAnimationId.Value, false, default(Vector3)); } catch { try { localPlayer.DamagePlayer(num, true, true, (CauseOfDeath)0, 0, false, default(Vector3)); } catch { } } } private static bool AppliesTo(DoorKind kind) { return Plugin.Config.AffectedDoors.Value switch { AffectedDoors.ShipDoor => kind == DoorKind.Ship, AffectedDoors.TerminalDoors => kind == DoorKind.Terminal, _ => true, }; } } public readonly struct DoorZone { public readonly Vector3 Center; public readonly Quaternion Rot; public readonly Vector3 HalfExtents; public DoorZone(Vector3 center, Quaternion rot, Vector3 halfExtents) { //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_0009: 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_0010: Unknown result type (might be due to invalid IL or missing references) Center = center; Rot = rot; HalfExtents = halfExtents; } public Vector3 ToLocal(Vector3 world) { //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_000b: 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) return Quaternion.Inverse(Rot) * (world - Center); } public bool Contains(Vector3 world) { //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_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_0020: 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 = ToLocal(world); if (Mathf.Abs(val.x) <= HalfExtents.x && Mathf.Abs(val.y) <= HalfExtents.y) { return Mathf.Abs(val.z) <= HalfExtents.z; } return false; } public static DoorZone FromThroughAxis(Vector3 center, Vector3 throughAxis, float width, float height, float thickness) { //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_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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_0021: Unknown result type (might be due to invalid IL or missing references) Vector3 val = throughAxis; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { val = Vector3.forward; } Quaternion rot = Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up); return new DoorZone(center, rot, new Vector3(width * 0.5f, height * 0.5f, thickness * 0.5f)); } } internal static class EnemyWhitelist { private static string[] _excluded = Array.Empty<string>(); private static string _cachedRaw; private static void RefreshCache() { string text = Plugin.Config.ExcludedEnemies.Value ?? string.Empty; if (!(text == _cachedRaw)) { _cachedRaw = text; _excluded = (from s in text.Split(',') select s.Trim().ToLowerInvariant() into s where s.Length > 0 select s).ToArray(); } } public static bool CanBeCrushed(EnemyAI enemy) { if ((Object)(object)enemy == (Object)null || GameCompat.IsEnemyDead(enemy)) { return false; } RefreshCache(); string text = GameCompat.EnemyName(enemy).ToLowerInvariant(); string[] excluded = _excluded; foreach (string value in excluded) { if (text.Contains(value)) { return false; } } return true; } } public sealed class LethalDoorsSession : MonoBehaviour { private float _landedTime = -9999f; private bool _prevLanded; public static LethalDoorsSession Instance { get; private set; } public bool InSafePeriod { get { float value = Plugin.Config.SafeZoneSeconds.Value; if (value <= 0f) { return false; } return Time.time - _landedTime < value; } } private void Awake() { Instance = this; } private void Update() { StartOfRound instance = StartOfRound.Instance; if (!((Object)(object)instance == (Object)null)) { bool shipHasLanded = instance.shipHasLanded; if (shipHasLanded && !_prevLanded) { _landedTime = Time.time; } _prevLanded = shipHasLanded; TerminalDoorCrush.Tick(); } } } internal static class TerminalDoorCrush { private sealed class Tracked { public TerminalAccessibleObject Door; public float CloseTime; public bool Crushed; public float DotAccumulator; } private static readonly List<Tracked> _tracked = new List<Tracked>(); public static void OnClosed(TerminalAccessibleObject door) { if ((Object)(object)door == (Object)null) { return; } for (int i = 0; i < _tracked.Count; i++) { if ((Object)(object)_tracked[i].Door == (Object)(object)door) { _tracked[i].CloseTime = Time.time; _tracked[i].Crushed = false; _tracked[i].DotAccumulator = 0f; return; } } _tracked.Add(new Tracked { Door = door, CloseTime = Time.time }); Plugin.Log.LogInfo((object)("Terminal door '" + ((Object)((Component)door).gameObject).name + "' closing — tracking for crush.")); } public static void Tick() { if (_tracked.Count == 0) { return; } float value = Plugin.Config.TerminalDoorCloseSeconds.Value; for (int num = _tracked.Count - 1; num >= 0; num--) { Tracked tracked = _tracked[num]; if ((Object)(object)tracked.Door == (Object)null || tracked.Door.isDoorOpen) { _tracked.RemoveAt(num); } else if (!(Time.time - tracked.CloseTime < value)) { DoorZone zone = BuildTerminalZone(tracked.Door); if (Plugin.Config.DamageMode.Value == DamageMode.DamageOverTime) { DoorCrushManager.ExecuteDamageTick(DoorKind.Terminal, zone, ref tracked.DotAccumulator); } else if (!tracked.Crushed) { tracked.Crushed = true; DoorCrushManager.ExecuteCrush(DoorKind.Terminal, zone); } } } } public static void Clear() { _tracked.Clear(); } private static DoorZone BuildTerminalZone(TerminalAccessibleObject door) { //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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) ModConfig config = Plugin.Config; Vector3 center = ((Component)door).transform.position + Vector3.up * (config.DoorwayHeight.Value * 0.25f); Vector3 forward = ((Component)door).transform.forward; return DoorZone.FromThroughAxis(center, forward, config.DoorwayWidth.Value, config.DoorwayHeight.Value, config.DoorwayThickness.Value); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { internal IgnoresAccessChecksToAttribute(string assemblyName) { } } }