Decompiled source of Terminal that can kill v1.0.9

plugins/Solon.TerminalThatCanKill.dll

Decompiled 16 hours ago
using 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)
		{
		}
	}
}