Decompiled source of LethalBattleTweaks v1.0.4

LethalBattleTweaks.dll

Decompiled 6 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CombatSharedFeatures;
using GameNetcodeStuff;
using HarmonyLib;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("LethalBattleTweaks")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("lengjing")]
[assembly: AssemblyProduct("LethalBattleTweaks")]
[assembly: AssemblyCopyright("Copyright © lengjing 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("8e5a2c62-6a18-4f9e-8948-596a50b89631")]
[assembly: AssemblyFileVersion("1.0.7.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.7.0")]
namespace CombatSharedFeatures
{
	public static class PublicFeatureConfig
	{
		public static ConfigEntry<bool> RefillEnabled { get; private set; }

		public static ConfigEntry<float> RefillInterval { get; private set; }

		public static ConfigEntry<int> RefillTotalCap { get; private set; }

		public static ConfigEntry<int> RefillDelay { get; private set; }

		public static ConfigEntry<float> SpawnDelay { get; private set; }

		public static ConfigEntry<int> RefillBatchSize { get; private set; }

		public static ConfigEntry<int> RefillFlowermanInit { get; private set; }

		public static ConfigEntry<int> RefillFlowermanMax { get; private set; }

		public static ConfigEntry<int> RefillFlowermanWeight { get; private set; }

		public static ConfigEntry<int> RefillNutcrackerInit { get; private set; }

		public static ConfigEntry<int> RefillNutcrackerMax { get; private set; }

		public static ConfigEntry<int> RefillNutcrackerWeight { get; private set; }

		public static ConfigEntry<int> RefillCrawlerInit { get; private set; }

		public static ConfigEntry<int> RefillCrawlerMax { get; private set; }

		public static ConfigEntry<int> RefillCrawlerWeight { get; private set; }

		public static ConfigEntry<int> RefillCentipedeInit { get; private set; }

		public static ConfigEntry<int> RefillCentipedeMax { get; private set; }

		public static ConfigEntry<int> RefillCentipedeWeight { get; private set; }

		public static ConfigEntry<int> RefillHoarderBugInit { get; private set; }

		public static ConfigEntry<int> RefillHoarderBugMax { get; private set; }

		public static ConfigEntry<int> RefillHoarderBugWeight { get; private set; }

		public static ConfigEntry<int> RefillMaskedInit { get; private set; }

		public static ConfigEntry<int> RefillMaskedMax { get; private set; }

		public static ConfigEntry<int> RefillMaskedWeight { get; private set; }

		public static ConfigEntry<int> RefillSandSpiderInit { get; private set; }

		public static ConfigEntry<int> RefillSandSpiderMax { get; private set; }

		public static ConfigEntry<int> RefillSandSpiderWeight { get; private set; }

		public static ConfigEntry<int> RefillButlerInit { get; private set; }

		public static ConfigEntry<int> RefillButlerMax { get; private set; }

		public static ConfigEntry<int> RefillButlerWeight { get; private set; }

		public static ConfigEntry<int> RefillStingrayInit { get; private set; }

		public static ConfigEntry<int> RefillStingrayMax { get; private set; }

		public static ConfigEntry<int> RefillStingrayWeight { get; private set; }

		public static ConfigEntry<int> StartingCredits { get; private set; }

		public static ConfigEntry<bool> DisableHazards { get; private set; }

		public static ConfigEntry<bool> DisableVanillaEnemies { get; private set; }

		public static ConfigEntry<bool> DisableScrap { get; private set; }

		public static ConfigEntry<bool> NoLockedDoors { get; private set; }

		public static ConfigEntry<bool> DisableFriendlyMeleeDamage { get; private set; }

		public static ConfigEntry<bool> ButlerInstantOpenDoors { get; private set; }

		public static ConfigEntry<bool> NutcrackerNoFriendlyFire { get; private set; }

		public static ConfigEntry<bool> NutcrackerDropGunAndShells { get; private set; }

		public static ConfigEntry<bool> ButlerDropKnifeAndBees { get; private set; }

		public static ConfigEntry<bool> TZPHealingEnabled { get; private set; }

		public static ConfigEntry<int> TZPHealAmount { get; private set; }

		public static ConfigEntry<bool> LootDropsEnabled { get; private set; }

		public static ConfigEntry<float> TZPDropChance { get; private set; }

		public static ConfigEntry<float> StunGrenadeDropChance { get; private set; }

		public static ConfigEntry<bool> CorpseCleanupEnabled { get; private set; }

		public static ConfigEntry<float> CorpseCleanupDelay { get; private set; }

		public static ConfigEntry<bool> CurfewEnabled { get; private set; }

		public static ConfigEntry<float> CurfewDuration { get; private set; }

		public static ConfigEntry<float> CurfewRepeatInterval { get; private set; }

		public static ConfigEntry<bool> ScoreboardEnabled { get; private set; }

		public static ConfigEntry<bool> MvpEnabled { get; private set; }

		public static ConfigEntry<Key> ScoreboardKey { get; private set; }

		public static ConfigEntry<int> ScoreWeight { get; private set; }

		public static ConfigEntry<int> HitWeight { get; private set; }

		public static ConfigEntry<bool> ScoreboardBroadcastEnabled { get; private set; }

		public static ConfigEntry<float> ScoreboardBroadcastInterval { get; private set; }

		public static ConfigEntry<int> ScoreboardBroadcastTopCount { get; private set; }

		public static ConfigEntry<int> ScoreFlowerman { get; private set; }

		public static ConfigEntry<int> ScoreNutcracker { get; private set; }

		public static ConfigEntry<int> ScoreCrawler { get; private set; }

		public static ConfigEntry<int> ScoreCentipede { get; private set; }

		public static ConfigEntry<int> ScoreHoarderBug { get; private set; }

		public static ConfigEntry<int> ScoreMasked { get; private set; }

		public static ConfigEntry<int> ScoreSandSpider { get; private set; }

		public static ConfigEntry<int> ScoreButler { get; private set; }

		public static ConfigEntry<int> ScoreStingray { get; private set; }

		public static ConfigEntry<bool> RescueEnabled { get; private set; }

		public static ConfigEntry<float> RescueImmunityDuration { get; private set; }

		public static ConfigEntry<bool> EnableCrawlerScale { get; private set; }

		public static ConfigEntry<float> CrawlerScale { get; private set; }

		public static ConfigEntry<bool> EnableButlerScale { get; private set; }

		public static ConfigEntry<float> ButlerScale { get; private set; }

		private static string Bilingual(string en, string zh)
		{
			return en + " / " + zh;
		}

		public static void Bind(ConfigFile config)
		{
			//IL_08d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_08dc: Expected O, but got Unknown
			//IL_0909: Unknown result type (might be due to invalid IL or missing references)
			//IL_0913: Expected O, but got Unknown
			//IL_0abd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ac7: Expected O, but got Unknown
			//IL_0b24: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b2e: Expected O, but got Unknown
			//IL_0b8b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b95: Expected O, but got Unknown
			string text = "Enemy Refill";
			RefillEnabled = config.Bind<bool>(text, "Enabled", true, Bilingual("Enable dynamic indoor enemy refill.", "启用设施内动态补怪。"));
			RefillInterval = config.Bind<float>(text, "Interval", 5f, Bilingual("Seconds between refill checks.", "每次检查是否需要补怪的间隔秒数。"));
			RefillTotalCap = config.Bind<int>(text, "TotalCap", 18, Bilingual("Total indoor enemies the refill system tries to maintain.", "补怪系统尝试维持的设施内怪物总上限。"));
			RefillDelay = config.Bind<int>(text, "RefillDelay", 10, Bilingual("Delay after landing before refill starts.", "飞船落地后开始补怪前的延迟秒数。"));
			SpawnDelay = config.Bind<float>(text, "SpawnDelay", 0.3f, Bilingual("Delay between spawned enemies during a refill batch.", "单次补怪批次中每只怪之间的生成间隔。"));
			RefillBatchSize = config.Bind<int>(text, "BatchSize", 3, Bilingual("Maximum enemies spawned per refill batch.", "每次补怪批次最多生成的怪物数量。"));
			RefillFlowermanInit = config.Bind<int>("Enemy Refill - Flowerman", "Init", 0, Bilingual("Initial Flowerman count.", "开局额外生成的小黑数量。"));
			RefillFlowermanMax = config.Bind<int>("Enemy Refill - Flowerman", "Max", 1, Bilingual("Maximum Flowerman refill count.", "小黑可被补怪到的最大数量。"));
			RefillFlowermanWeight = config.Bind<int>("Enemy Refill - Flowerman", "Weight", 10, Bilingual("Flowerman refill weight.", "小黑的补怪权重。"));
			RefillNutcrackerInit = config.Bind<int>("Enemy Refill - Nutcracker", "Init", 0, Bilingual("Initial Nutcracker count.", "开局额外生成的胡桃夹子数量。"));
			RefillNutcrackerMax = config.Bind<int>("Enemy Refill - Nutcracker", "Max", 1, Bilingual("Maximum Nutcracker refill count.", "胡桃夹子可被补怪到的最大数量。"));
			RefillNutcrackerWeight = config.Bind<int>("Enemy Refill - Nutcracker", "Weight", 10, Bilingual("Nutcracker refill weight.", "胡桃夹子的补怪权重。"));
			RefillCrawlerInit = config.Bind<int>("Enemy Refill - Crawler", "Init", 0, Bilingual("Initial Crawler count.", "开局额外生成的半身鱼数量。"));
			RefillCrawlerMax = config.Bind<int>("Enemy Refill - Crawler", "Max", 1, Bilingual("Maximum Crawler refill count.", "半身鱼可被补怪到的最大数量。"));
			RefillCrawlerWeight = config.Bind<int>("Enemy Refill - Crawler", "Weight", 10, Bilingual("Crawler refill weight.", "半身鱼的补怪权重。"));
			RefillCentipedeInit = config.Bind<int>("Enemy Refill - Centipede", "Init", 0, Bilingual("Initial Centipede count.", "开局额外生成的抱脸虫数量。"));
			RefillCentipedeMax = config.Bind<int>("Enemy Refill - Centipede", "Max", 2, Bilingual("Maximum Centipede refill count.", "抱脸虫可被补怪到的最大数量。"));
			RefillCentipedeWeight = config.Bind<int>("Enemy Refill - Centipede", "Weight", 10, Bilingual("Centipede refill weight.", "抱脸虫的补怪权重。"));
			RefillHoarderBugInit = config.Bind<int>("Enemy Refill - HoarderBug", "Init", 0, Bilingual("Initial HoarderBug count.", "开局额外生成的囤积虫数量。"));
			RefillHoarderBugMax = config.Bind<int>("Enemy Refill - HoarderBug", "Max", 3, Bilingual("Maximum HoarderBug refill count.", "囤积虫可被补怪到的最大数量。"));
			RefillHoarderBugWeight = config.Bind<int>("Enemy Refill - HoarderBug", "Weight", 10, Bilingual("HoarderBug refill weight.", "囤积虫的补怪权重。"));
			RefillMaskedInit = config.Bind<int>("Enemy Refill - Masked", "Init", 0, Bilingual("Initial Masked count.", "开局额外生成的假人数量。"));
			RefillMaskedMax = config.Bind<int>("Enemy Refill - Masked", "Max", 1, Bilingual("Maximum Masked refill count.", "假人可被补怪到的最大数量。"));
			RefillMaskedWeight = config.Bind<int>("Enemy Refill - Masked", "Weight", 10, Bilingual("Masked refill weight.", "假人的补怪权重。"));
			RefillSandSpiderInit = config.Bind<int>("Enemy Refill - SandSpider", "Init", 0, Bilingual("Initial SandSpider count.", "开局额外生成的蜘蛛数量。"));
			RefillSandSpiderMax = config.Bind<int>("Enemy Refill - SandSpider", "Max", 2, Bilingual("Maximum SandSpider refill count.", "蜘蛛可被补怪到的最大数量。"));
			RefillSandSpiderWeight = config.Bind<int>("Enemy Refill - SandSpider", "Weight", 10, Bilingual("SandSpider refill weight.", "蜘蛛的补怪权重。"));
			RefillButlerInit = config.Bind<int>("Enemy Refill - Butler", "Init", 0, Bilingual("Initial Butler count.", "开局额外生成的管家数量。"));
			RefillButlerMax = config.Bind<int>("Enemy Refill - Butler", "Max", 2, Bilingual("Maximum Butler refill count.", "管家可被补怪到的最大数量。"));
			RefillButlerWeight = config.Bind<int>("Enemy Refill - Butler", "Weight", 10, Bilingual("Butler refill weight.", "管家的补怪权重。"));
			RefillStingrayInit = config.Bind<int>("Enemy Refill - Stingray", "Init", 0, Bilingual("Initial Stingray count.", "开局额外生成的黏滑鱼数量。"));
			RefillStingrayMax = config.Bind<int>("Enemy Refill - Stingray", "Max", 1, Bilingual("Maximum Stingray refill count.", "黏滑鱼可被补怪到的最大数量。"));
			RefillStingrayWeight = config.Bind<int>("Enemy Refill - Stingray", "Weight", 10, Bilingual("Stingray refill weight.", "黏滑鱼的补怪权重。"));
			StartingCredits = config.Bind<int>("World Rules", "StartingCredits", 60, Bilingual("Starting company credits.", "开局公司金钱。"));
			DisableHazards = config.Bind<bool>("World Rules", "DisableHazards", false, Bilingual("Disable landmines, turrets, and spikes.", "禁用地雷、炮塔和尖刺。"));
			DisableVanillaEnemies = config.Bind<bool>("World Rules", "DisableVanillaEnemies", false, Bilingual("Disable vanilla natural enemy spawning.", "禁用原版自然刷怪。"));
			DisableScrap = config.Bind<bool>("World Rules", "DisableScrap", false, Bilingual("Disable indoor scrap spawning.", "禁用室内废料刷新。"));
			NoLockedDoors = config.Bind<bool>("World Rules", "NoLockedDoors", true, Bilingual("Automatically unlock locked doors.", "自动解锁上锁的门。"));
			DisableFriendlyMeleeDamage = config.Bind<bool>("World Rules", "DisableFriendlyMeleeDamage", true, Bilingual("Disable shovel and knife friendly fire.", "禁用铲子和小刀的玩家友伤。"));
			ButlerInstantOpenDoors = config.Bind<bool>("World Rules", "ButlerInstantOpenDoors", true, Bilingual("Make butlers open doors almost instantly.", "让管家几乎瞬间开门。"));
			NutcrackerNoFriendlyFire = config.Bind<bool>("World Rules", "NutcrackerNoFriendlyFire", true, Bilingual("Prevent nutcracker shotgun blasts from damaging monsters while still allowing player damage.", "让胡桃夹子不会伤害怪物,但仍然可以伤害玩家。"));
			NutcrackerDropGunAndShells = config.Bind<bool>("World Rules", "NutcrackerDropGunAndShells", false, Bilingual("Allow nutcrackers to drop their shotgun and shotgun shells on death.", "允许胡桃夹子死亡时掉落枪和子弹。"));
			ButlerDropKnifeAndBees = config.Bind<bool>("World Rules", "ButlerDropKnifeAndBees", false, Bilingual("Allow butlers to spawn their knife and bees on death.", "允许管家死亡时掉落菜刀并生成蜜蜂。"));
			TZPHealingEnabled = config.Bind<bool>("TZP Healing", "Enabled", true, Bilingual("Allow TZP inhalant to heal once per canister.", "允许每罐 TZP 提供一次回血。"));
			TZPHealAmount = config.Bind<int>("TZP Healing", "HealAmount", 20, Bilingual("Healing amount per TZP use.", "每次 TZP 触发时的回血量。"));
			LootDropsEnabled = config.Bind<bool>("Loot Drops", "Enabled", true, Bilingual("Allow enemies to drop combat supplies.", "允许敌人掉落战斗补给。"));
			TZPDropChance = config.Bind<float>("Loot Drops", "TZPDropChance", 0.1f, Bilingual("Chance for supported enemies to drop TZP.", "支持的敌人掉落 TZP 的概率。"));
			StunGrenadeDropChance = config.Bind<float>("Loot Drops", "StunGrenadeDropChance", 0.05f, Bilingual("Chance for supported enemies to drop a stun grenade.", "支持的敌人掉落闪光弹的概率。"));
			CorpseCleanupEnabled = config.Bind<bool>("Corpse Cleanup", "Enabled", true, Bilingual("Automatically remove enemy corpses after a delay.", "延迟一段时间后自动清理怪物尸体。"));
			CorpseCleanupDelay = config.Bind<float>("Corpse Cleanup", "Delay", 5f, Bilingual("Delay in seconds before supported enemy corpses are removed.", "支持的怪物尸体在被清理前等待的秒数。"));
			CurfewEnabled = config.Bind<bool>("Curfew Execution", "Enabled", false, Bilingual("After landing, execute players who remain outside the facility after the timer, including players idling on the ship.", "飞船落地倒计时结束后处决仍在设施外的玩家,飞船内挂机玩家也会被处决。"));
			CurfewDuration = config.Bind<float>("Curfew Execution", "Duration", 60f, Bilingual("Seconds after landing before players outside the facility are condemned.", "飞船落地后多少秒开始处决设施外玩家。"));
			CurfewRepeatInterval = config.Bind<float>("Curfew Execution", "RepeatInterval", 5f, Bilingual("Seconds between judge dog retry attempts and outside checks.", "审判犬失败重试和室外检查的间隔秒数。"));
			ScoreboardEnabled = config.Bind<bool>("Combat Scoreboard", "Enabled", true, Bilingual("Enable the host combat scoreboard.", "启用主机战斗记分面板。"));
			MvpEnabled = config.Bind<bool>("Combat Scoreboard", "MvpEnabled", true, Bilingual("Broadcast the round MVP in chat at game over.", "游戏结束时在聊天栏播报本局 MVP。"));
			ScoreboardKey = config.Bind<Key>("Combat Scoreboard", "ToggleKey", (Key)16, Bilingual("Keyboard key used to show or hide the scoreboard.", "显示或隐藏记分面板的按键。"));
			ScoreWeight = config.Bind<int>("Combat Scoreboard", "ScoreWeight", 7, Bilingual("Weight of kill score in total score.", "击杀得分在总分中的权重。"));
			HitWeight = config.Bind<int>("Combat Scoreboard", "HitWeight", 3, Bilingual("Weight of hit count in total score.", "命中次数在总分中的权重。"));
			ScoreboardBroadcastEnabled = config.Bind<bool>("Scoreboard Broadcast", "Enabled", true, Bilingual("Broadcast the top players in chat.", "在聊天栏播报排名。"));
			ScoreboardBroadcastInterval = config.Bind<float>("Scoreboard Broadcast", "Interval", 10f, new ConfigDescription(Bilingual("Seconds between ranking broadcasts.", "排名播报间隔秒数。"), (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 300f), Array.Empty<object>()));
			ScoreboardBroadcastTopCount = config.Bind<int>("Scoreboard Broadcast", "TopCount", 3, new ConfigDescription(Bilingual("Number of top players to broadcast.", "聊天栏播报前几名。"), (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>()));
			ScoreFlowerman = config.Bind<int>("Combat Scoring", "Flowerman", 3, Bilingual("Score for killing a Flowerman.", "击杀小黑的得分。"));
			ScoreNutcracker = config.Bind<int>("Combat Scoring", "Nutcracker", 2, Bilingual("Score for killing a Nutcracker.", "击杀胡桃夹子的得分。"));
			ScoreCrawler = config.Bind<int>("Combat Scoring", "Crawler", 2, Bilingual("Score for killing a Crawler.", "击杀半身鱼的得分。"));
			ScoreCentipede = config.Bind<int>("Combat Scoring", "Centipede", 1, Bilingual("Score for killing a Centipede.", "击杀抱脸虫的得分。"));
			ScoreHoarderBug = config.Bind<int>("Combat Scoring", "HoarderBug", 1, Bilingual("Score for killing a Hoarder Bug.", "击杀囤积虫的得分。"));
			ScoreMasked = config.Bind<int>("Combat Scoring", "Masked", 1, Bilingual("Score for killing a Masked enemy.", "击杀假人的得分。"));
			ScoreSandSpider = config.Bind<int>("Combat Scoring", "SandSpider", 2, Bilingual("Score for killing a Sand Spider.", "击杀蜘蛛的得分。"));
			ScoreButler = config.Bind<int>("Combat Scoring", "Butler", 2, Bilingual("Score for killing a Butler.", "击杀管家的得分。"));
			ScoreStingray = config.Bind<int>("Combat Scoring", "Stingray", 2, Bilingual("Score for killing a Stingray.", "击杀黏滑鱼的得分。"));
			RescueEnabled = config.Bind<bool>("Rescue", "Enabled", true, Bilingual("Allow the host to rescue an outside player with the ship teleporter.", "允许主机使用飞船传送器救援设施外玩家。"));
			RescueImmunityDuration = config.Bind<float>("Rescue", "ImmunityDuration", 45f, new ConfigDescription(Bilingual("Seconds of curfew immunity after a successful rescue.", "成功救援后免处决的秒数。"), (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 300f), Array.Empty<object>()));
			EnableCrawlerScale = config.Bind<bool>("Enemy Scale", "EnableCrawlerScale", false, Bilingual("Enable Crawler scaling.", "启用半身鱼体型放大。"));
			CrawlerScale = config.Bind<float>("Enemy Scale", "CrawlerScale", 1.5f, new ConfigDescription(Bilingual("Crawler local scale multiplier.", "半身鱼体型倍率。"), (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 2f), Array.Empty<object>()));
			EnableButlerScale = config.Bind<bool>("Enemy Scale", "EnableButlerScale", false, Bilingual("Enable Butler scaling.", "启用管家体型放大。"));
			ButlerScale = config.Bind<float>("Enemy Scale", "ButlerScale", 1.3f, new ConfigDescription(Bilingual("Butler local scale multiplier.", "管家体型倍率。"), (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 2f), Array.Empty<object>()));
		}
	}
	public enum PublicFeatureMode
	{
		PublicStandalone,
		PrivateExtended
	}
	public static class PublicFeatureRuntime
	{
		[HarmonyPatch(typeof(StartOfRound), "StartGame")]
		private static class StartOfRoundStartGamePatch
		{
			[HarmonyPrefix]
			private static void Prefix()
			{
				if (!((Object)(object)StartOfRound.Instance == (Object)null) && ((NetworkBehaviour)StartOfRound.Instance).IsServer)
				{
					HandleRoundStart();
				}
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "gameOverAnimation")]
		private static class GameOverAnimationPatch
		{
			[HarmonyPostfix]
			private static void Postfix()
			{
				CombatScoreboardSystem.ScheduleMvpAnnouncement();
			}
		}

		[HarmonyPatch(typeof(RoundManager), "DespawnPropsAtEndOfRound")]
		private static class RoundEndPatch
		{
			[HarmonyPrefix]
			private static void Prefix()
			{
				CombatScoreboardSystem.EndRound();
				CurfewExecutionSystem.Stop();
			}
		}

		private static BaseUnityPlugin _plugin;

		private static ConfigFile _config;

		private static Func<EnemyAI, bool> _privateBossPredicate;

		private static bool _isInitialized;

		private static ManualLogSource _logger = Logger.CreateLogSource("PublicFeatureRuntime");

		public static BaseUnityPlugin PluginInstance => _plugin;

		public static ManualLogSource Logger => _logger;

		public static PublicFeatureMode Mode { get; private set; }

		public static bool IsEnabled => _isInitialized;

		public static void Initialize(BaseUnityPlugin plugin, PublicFeatureMode mode, ManualLogSource logger)
		{
			if (!((Object)(object)_plugin == (Object)(object)plugin) || !_isInitialized)
			{
				_plugin = plugin;
				_config = plugin.Config;
				Mode = mode;
				_logger = logger ?? _logger;
				PublicFeatureConfig.Bind(_config);
				_config.SettingChanged += HandleConfigChanged;
				_isInitialized = true;
				CombatScoreboardSystem.Initialize();
			}
		}

		public static void OnPluginStart()
		{
			if (_isInitialized)
			{
				PublicFeatureEnemyCatalog.CacheAllEnemyTypes();
				RefillSystem.Restart();
			}
		}

		public static void Shutdown()
		{
			if (_isInitialized)
			{
				RefillSystem.Stop();
				CurfewExecutionSystem.Stop();
				CombatScoreboardSystem.Stop();
				EnemyScalePatches.ResetRoundState();
				if (_config != null)
				{
					_config.SettingChanged -= HandleConfigChanged;
				}
				_plugin = null;
				_config = null;
				_privateBossPredicate = null;
				_isInitialized = false;
			}
		}

		public static void HandleRoundStart()
		{
			if (_isInitialized)
			{
				PublicFeatureEnemyCatalog.CacheAllEnemyTypes();
				ItemAndLootPatches.ResetRoundState();
				CurfewExecutionSystem.ResetRoundState();
				CombatScoreboardSystem.ResetRoundState();
				EnemyScalePatches.ResetRoundState();
				RefillSystem.Restart();
				CurfewExecutionSystem.Restart();
				CombatScoreboardSystem.StartBroadcast();
			}
		}

		public static void HandleConfigChanged(object sender, SettingChangedEventArgs e)
		{
			if (_isInitialized && e != null && e.ChangedSetting != null)
			{
				string text = e.ChangedSetting.Definition.Section ?? string.Empty;
				if (text.StartsWith("Enemy Refill", StringComparison.OrdinalIgnoreCase))
				{
					RefillSystem.Restart();
				}
				else if (text.StartsWith("Combat Scoreboard", StringComparison.OrdinalIgnoreCase) || text.StartsWith("Combat Scoring", StringComparison.OrdinalIgnoreCase))
				{
					CombatScoreboardSystem.ResetRoundState();
				}
				else if (text.StartsWith("Curfew Execution", StringComparison.OrdinalIgnoreCase))
				{
					CurfewExecutionSystem.Restart();
				}
				else if (text.StartsWith("Scoreboard Broadcast", StringComparison.OrdinalIgnoreCase))
				{
					CombatScoreboardSystem.RestartBroadcast();
				}
			}
		}

		public static void SetPrivateBossPredicate(Func<EnemyAI, bool> predicate)
		{
			_privateBossPredicate = predicate;
		}

		public static bool IsPrivateBossEnemy(EnemyAI enemy)
		{
			if (_privateBossPredicate != null && (Object)(object)enemy != (Object)null)
			{
				return _privateBossPredicate(enemy);
			}
			return false;
		}
	}
	public static class PublicFeatureEnemyCatalog
	{
		private static readonly Dictionary<string, EnemyType> EnemyTypeCache = new Dictionary<string, EnemyType>();

		private static readonly Dictionary<string, string> EnemyNameAliases = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
		{
			{ "HoarderBug", "Hoarding bug" },
			{ "SandSpider", "Bunker Spider" },
			{ "Masked", "Masked" },
			{ "Centipede", "Centipede" },
			{ "Flowerman", "Flowerman" },
			{ "Nutcracker", "Nutcracker" },
			{ "Crawler", "Crawler" },
			{ "Butler", "Butler" },
			{ "Stingray", "Stingray" }
		};

		public static int CachedEnemyCount => EnemyTypeCache.Count;

		public static void CacheAllEnemyTypes()
		{
			if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.levels == null)
			{
				return;
			}
			EnemyTypeCache.Clear();
			SelectableLevel[] levels = StartOfRound.Instance.levels;
			foreach (SelectableLevel val in levels)
			{
				foreach (SpawnableEnemyWithRarity enemy in val.Enemies)
				{
					CacheEnemyType(enemy.enemyType);
				}
				foreach (SpawnableEnemyWithRarity daytimeEnemy in val.DaytimeEnemies)
				{
					CacheEnemyType(daytimeEnemy.enemyType);
				}
				foreach (SpawnableEnemyWithRarity outsideEnemy in val.OutsideEnemies)
				{
					CacheEnemyType(outsideEnemy.enemyType);
				}
			}
		}

		public static EnemyType GetEnemyTypeByName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return null;
			}
			string text = name;
			if (EnemyNameAliases.TryGetValue(name, out var value))
			{
				text = value;
			}
			if (EnemyTypeCache.TryGetValue(text, out var value2))
			{
				return value2;
			}
			if (text != name && EnemyTypeCache.TryGetValue(name, out value2))
			{
				return value2;
			}
			foreach (KeyValuePair<string, EnemyType> item in EnemyTypeCache)
			{
				if (item.Key.Equals(text, StringComparison.OrdinalIgnoreCase) || item.Key.Equals(name, StringComparison.OrdinalIgnoreCase))
				{
					return item.Value;
				}
			}
			foreach (KeyValuePair<string, EnemyType> item2 in EnemyTypeCache)
			{
				if (item2.Key.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0 || item2.Key.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return item2.Value;
				}
			}
			return null;
		}

		private static void CacheEnemyType(EnemyType type)
		{
			if (!((Object)(object)type == (Object)null) && !EnemyTypeCache.ContainsKey(type.enemyName))
			{
				EnemyTypeCache[type.enemyName] = type;
			}
		}
	}
	public static class RefillSystem
	{
		private struct MonsterConfig
		{
			public string Name;

			public int Init;

			public int Max;

			public int Weight;

			public MonsterConfig(string name, int init, int max, int weight)
			{
				Name = name;
				Init = init;
				Max = max;
				Weight = weight;
			}
		}

		private static readonly List<MonsterConfig> CachedRefillConfigs = new List<MonsterConfig>();

		private static readonly List<(MonsterConfig Config, float Score)> RefillCandidatesBuffer = new List<(MonsterConfig, float)>();

		private static readonly List<int> ValidSpawnNodesBuffer = new List<int>();

		private static Coroutine _refillCoroutine;

		public static void Restart()
		{
			Stop();
			if ((Object)(object)PublicFeatureRuntime.PluginInstance != (Object)null && PublicFeatureConfig.RefillEnabled.Value)
			{
				_refillCoroutine = ((MonoBehaviour)PublicFeatureRuntime.PluginInstance).StartCoroutine(RefillEnemiesRoutine());
			}
		}

		public static void Stop()
		{
			if (_refillCoroutine != null && (Object)(object)PublicFeatureRuntime.PluginInstance != (Object)null)
			{
				((MonoBehaviour)PublicFeatureRuntime.PluginInstance).StopCoroutine(_refillCoroutine);
				_refillCoroutine = null;
			}
		}

		private static IEnumerator RefillEnemiesRoutine()
		{
			while ((Object)(object)RoundManager.Instance == (Object)null)
			{
				yield return (object)new WaitForSeconds(1f);
			}
			while (!((Object)(object)StartOfRound.Instance == (Object)null) && !((Object)(object)RoundManager.Instance == (Object)null))
			{
				yield return (object)new WaitUntil((Func<bool>)(() => (Object)(object)StartOfRound.Instance == (Object)null || (StartOfRound.Instance.shipHasLanded && !StartOfRound.Instance.inShipPhase && RoundManager.Instance.allEnemyVents != null && RoundManager.Instance.allEnemyVents.Length != 0)));
				if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)RoundManager.Instance == (Object)null)
				{
					break;
				}
				if (!PublicFeatureConfig.RefillEnabled.Value || !((NetworkBehaviour)RoundManager.Instance).IsHost)
				{
					yield return (object)new WaitForSeconds(1f);
					continue;
				}
				if (PublicFeatureEnemyCatalog.CachedEnemyCount == 0)
				{
					PublicFeatureEnemyCatalog.CacheAllEnemyTypes();
				}
				yield return SpawnInitialEnemiesCoroutine();
				for (float elapsed = 0f; elapsed < (float)PublicFeatureConfig.RefillDelay.Value; elapsed += 1f)
				{
					if ((Object)(object)StartOfRound.Instance == (Object)null)
					{
						break;
					}
					if (StartOfRound.Instance.inShipPhase)
					{
						break;
					}
					yield return (object)new WaitForSeconds(1f);
				}
				if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.inShipPhase)
				{
					continue;
				}
				while ((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.shipHasLanded && !StartOfRound.Instance.inShipPhase)
				{
					if (PublicFeatureConfig.RefillEnabled.Value)
					{
						yield return CheckAndRefillEnemiesCoroutine();
					}
					yield return (object)new WaitForSeconds(PublicFeatureConfig.RefillInterval.Value);
					if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.inShipPhase)
					{
						break;
					}
				}
			}
		}

		private static IEnumerator SpawnInitialEnemiesCoroutine()
		{
			List<MonsterConfig> monsterConfigs = GetMonsterConfigs();
			foreach (MonsterConfig item in monsterConfigs)
			{
				if ((Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.inShipPhase)
				{
					yield break;
				}
				if (item.Init > 0)
				{
					EnemyType enemyTypeByName = PublicFeatureEnemyCatalog.GetEnemyTypeByName(item.Name);
					if ((Object)(object)enemyTypeByName != (Object)null)
					{
						yield return SpawnEnemyCoroutine(enemyTypeByName, item.Init);
					}
				}
			}
		}

		private static IEnumerator CheckAndRefillEnemiesCoroutine()
		{
			if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)RoundManager.Instance == (Object)null)
			{
				yield break;
			}
			List<MonsterConfig> monsterConfigs = GetMonsterConfigs();
			Dictionary<string, EnemyType> configTypeMap = new Dictionary<string, EnemyType>();
			foreach (MonsterConfig item2 in monsterConfigs)
			{
				configTypeMap[item2.Name] = PublicFeatureEnemyCatalog.GetEnemyTypeByName(item2.Name);
			}
			List<EnemyAI> spawnedEnemies = RoundManager.Instance.SpawnedEnemies;
			int num = 0;
			Dictionary<string, int> currentCounts = new Dictionary<string, int>();
			foreach (MonsterConfig item3 in monsterConfigs)
			{
				currentCounts[item3.Name] = 0;
			}
			for (int i = 0; i < spawnedEnemies.Count; i++)
			{
				EnemyAI val = spawnedEnemies[i];
				if ((Object)(object)val == (Object)null || val.isEnemyDead)
				{
					continue;
				}
				foreach (MonsterConfig item4 in monsterConfigs)
				{
					EnemyType val2 = configTypeMap[item4.Name];
					if ((Object)(object)val2 != (Object)null && (Object)(object)val.enemyType == (Object)(object)val2)
					{
						currentCounts[item4.Name]++;
						num++;
						break;
					}
				}
			}
			int num2 = PublicFeatureConfig.RefillTotalCap.Value - num;
			if (num2 <= 0)
			{
				yield break;
			}
			int toSpawn = Mathf.Min(num2, PublicFeatureConfig.RefillBatchSize.Value);
			for (int j = 0; j < toSpawn; j++)
			{
				RefillCandidatesBuffer.Clear();
				foreach (MonsterConfig item5 in monsterConfigs)
				{
					if (currentCounts[item5.Name] < item5.Max && item5.Weight > 0)
					{
						float item = (float)item5.Weight / (float)(currentCounts[item5.Name] + 1);
						RefillCandidatesBuffer.Add((item5, item));
					}
				}
				if (RefillCandidatesBuffer.Count == 0)
				{
					break;
				}
				float num3 = 0f;
				foreach (var item6 in RefillCandidatesBuffer)
				{
					num3 += item6.Score;
				}
				float num4 = Random.Range(0f, num3);
				MonsterConfig selectedConfig = RefillCandidatesBuffer.Last().Config;
				float num5 = 0f;
				foreach (var item7 in RefillCandidatesBuffer)
				{
					num5 += item7.Score;
					if (num4 < num5)
					{
						(selectedConfig, _) = item7;
						break;
					}
				}
				EnemyType val3 = configTypeMap[selectedConfig.Name];
				if ((Object)(object)val3 != (Object)null)
				{
					yield return SpawnEnemyCoroutine(val3, 1);
					currentCounts[selectedConfig.Name]++;
				}
			}
		}

		private static List<MonsterConfig> GetMonsterConfigs()
		{
			CachedRefillConfigs.Clear();
			CachedRefillConfigs.Add(new MonsterConfig("Flowerman", PublicFeatureConfig.RefillFlowermanInit.Value, PublicFeatureConfig.RefillFlowermanMax.Value, PublicFeatureConfig.RefillFlowermanWeight.Value));
			CachedRefillConfigs.Add(new MonsterConfig("Nutcracker", PublicFeatureConfig.RefillNutcrackerInit.Value, PublicFeatureConfig.RefillNutcrackerMax.Value, PublicFeatureConfig.RefillNutcrackerWeight.Value));
			CachedRefillConfigs.Add(new MonsterConfig("Crawler", PublicFeatureConfig.RefillCrawlerInit.Value, PublicFeatureConfig.RefillCrawlerMax.Value, PublicFeatureConfig.RefillCrawlerWeight.Value));
			CachedRefillConfigs.Add(new MonsterConfig("Centipede", PublicFeatureConfig.RefillCentipedeInit.Value, PublicFeatureConfig.RefillCentipedeMax.Value, PublicFeatureConfig.RefillCentipedeWeight.Value));
			CachedRefillConfigs.Add(new MonsterConfig("HoarderBug", PublicFeatureConfig.RefillHoarderBugInit.Value, PublicFeatureConfig.RefillHoarderBugMax.Value, PublicFeatureConfig.RefillHoarderBugWeight.Value));
			CachedRefillConfigs.Add(new MonsterConfig("Masked", PublicFeatureConfig.RefillMaskedInit.Value, PublicFeatureConfig.RefillMaskedMax.Value, PublicFeatureConfig.RefillMaskedWeight.Value));
			CachedRefillConfigs.Add(new MonsterConfig("SandSpider", PublicFeatureConfig.RefillSandSpiderInit.Value, PublicFeatureConfig.RefillSandSpiderMax.Value, PublicFeatureConfig.RefillSandSpiderWeight.Value));
			CachedRefillConfigs.Add(new MonsterConfig("Butler", PublicFeatureConfig.RefillButlerInit.Value, PublicFeatureConfig.RefillButlerMax.Value, PublicFeatureConfig.RefillButlerWeight.Value));
			CachedRefillConfigs.Add(new MonsterConfig("Stingray", PublicFeatureConfig.RefillStingrayInit.Value, PublicFeatureConfig.RefillStingrayMax.Value, PublicFeatureConfig.RefillStingrayWeight.Value));
			return CachedRefillConfigs;
		}

		private static IEnumerator SpawnEnemyCoroutine(EnemyType type, int count)
		{
			if ((Object)(object)type == (Object)null || count <= 0 || (Object)(object)RoundManager.Instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null)
			{
				yield break;
			}
			GameObject[] aiNodes = RoundManager.Instance.insideAINodes;
			if (aiNodes == null || aiNodes.Length == 0)
			{
				yield break;
			}
			ValidSpawnNodesBuffer.Clear();
			for (int i = 0; i < aiNodes.Length; i++)
			{
				ValidSpawnNodesBuffer.Add(i);
			}
			for (int j = 0; j < count; j++)
			{
				if (ValidSpawnNodesBuffer.Count == 0)
				{
					for (int k = 0; k < aiNodes.Length; k++)
					{
						ValidSpawnNodesBuffer.Add(k);
					}
				}
				int index = Random.Range(0, ValidSpawnNodesBuffer.Count);
				int num = ValidSpawnNodesBuffer[index];
				GameObject val = aiNodes[num];
				if ((Object)(object)val == (Object)null)
				{
					ValidSpawnNodesBuffer.RemoveAt(index);
					j--;
					continue;
				}
				Vector3 position = val.transform.position;
				Quaternion val2 = Quaternion.Euler(0f, val.transform.eulerAngles.y, 0f);
				try
				{
					GameObject obj = Object.Instantiate<GameObject>(type.enemyPrefab, position, val2);
					obj.GetComponentInChildren<NetworkObject>().Spawn(true);
					EnemyAI component = obj.GetComponent<EnemyAI>();
					if ((Object)(object)component != (Object)null)
					{
						RoundManager.Instance.SpawnedEnemies.Add(component);
						component.enemyType.isOutsideEnemy = false;
						component.allAINodes = aiNodes;
						component.SyncPositionToClients();
						if (type.enemyName == "Flowerman")
						{
							component.EnableEnemyMesh(true, false, false);
						}
					}
					ValidSpawnNodesBuffer.RemoveAt(index);
				}
				catch (Exception arg)
				{
					PublicFeatureRuntime.Logger.LogError((object)$"[RefillSystem] Failed to spawn {type.enemyName}: {arg}");
				}
				if (j < count - 1)
				{
					yield return (object)new WaitForSeconds(PublicFeatureConfig.SpawnDelay.Value);
					if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)RoundManager.Instance == (Object)null || StartOfRound.Instance.inShipPhase)
					{
						break;
					}
				}
			}
		}
	}
	public static class CurfewExecutionSystem
	{
		private sealed class ExecutionTaskState
		{
			internal string Reason;

			internal int AttemptCount;

			internal float StartedAt;

			internal float NextRetryAt;

			internal bool PendingAnnounced;
		}

		private const string ExecutionReason = "怯战";

		private static readonly Vector3 JudgeDogHiddenPosition = new Vector3(0f, -500f, 0f);

		private static readonly Dictionary<ulong, ExecutionTaskState> CondemnedPlayers = new Dictionary<ulong, ExecutionTaskState>();

		private static readonly Dictionary<ulong, float> RescueImmunityExpiry = new Dictionary<ulong, float>();

		private static readonly HashSet<ulong> RescuedPlayersThisRound = new HashSet<ulong>();

		private static Coroutine _curfewCoroutine;

		private static Coroutine _executionCoroutine;

		private static Coroutine _rescueCoroutine;

		private static MouthDogAI _judgeDog;

		private static ulong? _activeExecutionTarget;

		private static int _judgeDogExecutionSerial;

		public static void Restart()
		{
			Stop();
			if (PublicFeatureRuntime.IsEnabled && PublicFeatureConfig.CurfewEnabled.Value && !((Object)(object)PublicFeatureRuntime.PluginInstance == (Object)null))
			{
				_curfewCoroutine = ((MonoBehaviour)PublicFeatureRuntime.PluginInstance).StartCoroutine(CurfewRoutine());
				_executionCoroutine = ((MonoBehaviour)PublicFeatureRuntime.PluginInstance).StartCoroutine(ProcessExecutionLoop());
			}
		}

		public static void Stop()
		{
			if ((Object)(object)PublicFeatureRuntime.PluginInstance != (Object)null)
			{
				if (_curfewCoroutine != null)
				{
					((MonoBehaviour)PublicFeatureRuntime.PluginInstance).StopCoroutine(_curfewCoroutine);
				}
				if (_executionCoroutine != null)
				{
					((MonoBehaviour)PublicFeatureRuntime.PluginInstance).StopCoroutine(_executionCoroutine);
				}
				if (_rescueCoroutine != null)
				{
					((MonoBehaviour)PublicFeatureRuntime.PluginInstance).StopCoroutine(_rescueCoroutine);
				}
			}
			_curfewCoroutine = null;
			_executionCoroutine = null;
			_rescueCoroutine = null;
		}

		public static void ResetRoundState()
		{
			CondemnedPlayers.Clear();
			RescueImmunityExpiry.Clear();
			RescuedPlayersThisRound.Clear();
			_activeExecutionTarget = null;
			_judgeDog = null;
			_judgeDogExecutionSerial = 0;
		}

		private static IEnumerator CurfewRoutine()
		{
			while ((Object)(object)TimeOfDay.Instance == (Object)null || (Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)RoundManager.Instance == (Object)null)
			{
				yield return null;
			}
			float duration = Mathf.Max(0f, PublicFeatureConfig.CurfewDuration.Value);
			HUDManager instance = HUDManager.Instance;
			if (instance != null)
			{
				instance.AddTextToChatOnServer("<color=red>可以怕,但不能怂," + FormatCurfewDuration(duration) + "s后在设施外的玩家将被无情处决</color>", -1);
			}
			while (!StartOfRound.Instance.shipHasLanded)
			{
				if (!CanWaitForLanding())
				{
					yield break;
				}
				yield return (object)new WaitForSeconds(0.5f);
			}
			float landingTime = Time.realtimeSinceStartup;
			while (Time.realtimeSinceStartup - landingTime < duration)
			{
				if (!IsRoundValidForCurfew())
				{
					yield break;
				}
				yield return (object)new WaitForSeconds(1f);
			}
			HUDManager instance2 = HUDManager.Instance;
			if (instance2 != null)
			{
				instance2.AddTextToChatOnServer("<color=red>处决开始!所有设施外人员将被无情处决</color>", -1);
			}
			while (IsRoundValidForCurfew())
			{
				CondemnOutsidePlayersOnce();
				yield return (object)new WaitForSeconds(Mathf.Max(1f, PublicFeatureConfig.CurfewRepeatInterval.Value));
			}
		}

		private static IEnumerator ProcessExecutionLoop()
		{
			while (PublicFeatureRuntime.IsEnabled && PublicFeatureConfig.CurfewEnabled.Value)
			{
				if (!IsRoundValidForCurfew())
				{
					yield return (object)new WaitForSeconds(1f);
					continue;
				}
				float time = Time.time;
				RemoveStaleCondemnedPlayers();
				if (_activeExecutionTarget.HasValue)
				{
					ProcessActiveExecutionTarget(time);
				}
				if (!_activeExecutionTarget.HasValue)
				{
					KeyValuePair<ulong, ExecutionTaskState> keyValuePair = CondemnedPlayers.OrderBy((KeyValuePair<ulong, ExecutionTaskState> kv) => kv.Value.StartedAt).FirstOrDefault();
					if (!keyValuePair.Equals(default(KeyValuePair<ulong, ExecutionTaskState>)))
					{
						_activeExecutionTarget = keyValuePair.Key;
					}
				}
				yield return (object)new WaitForSeconds(1f);
			}
		}

		private static void CondemnOutsidePlayersOnce()
		{
			if (StartOfRound.Instance?.allPlayerScripts == null)
			{
				return;
			}
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				if (!((Object)(object)val == (Object)null) && val.isPlayerControlled && !val.isPlayerDead && !val.isInsideFactory && !IsRescueImmune(val.playerClientId))
				{
					ExecutePlayer(val, "怯战");
				}
			}
		}

		private static void ExecutePlayer(PlayerControllerB player, string reason)
		{
			if (!((Object)(object)player == (Object)null) && !player.isPlayerDead)
			{
				if (CondemnedPlayers.TryGetValue(player.playerClientId, out var value))
				{
					value.Reason = reason;
					return;
				}
				CondemnedPlayers[player.playerClientId] = new ExecutionTaskState
				{
					Reason = reason,
					AttemptCount = 0,
					StartedAt = Time.time,
					NextRetryAt = Time.time,
					PendingAnnounced = false
				};
			}
		}

		private static void ProcessActiveExecutionTarget(float now)
		{
			ulong value = _activeExecutionTarget.Value;
			if (!CondemnedPlayers.TryGetValue(value, out var value2))
			{
				_activeExecutionTarget = null;
				return;
			}
			PlayerControllerB val = FindPlayer(value);
			if ((Object)(object)val == (Object)null)
			{
				CondemnedPlayers.Remove(value);
				_activeExecutionTarget = null;
			}
			else if (val.isPlayerDead)
			{
				HUDManager instance = HUDManager.Instance;
				if (instance != null)
				{
					instance.AddTextToChatOnServer("<color=red>" + val.playerUsername + "已被处决</color>", -1);
				}
				CondemnedPlayers.Remove(value);
				_activeExecutionTarget = null;
			}
			else if (IsRescueImmune(value) || val.isInsideFactory)
			{
				CondemnedPlayers.Remove(value);
				_activeExecutionTarget = null;
			}
			else
			{
				if (now < value2.NextRetryAt)
				{
					return;
				}
				if (!value2.PendingAnnounced)
				{
					HUDManager instance2 = HUDManager.Instance;
					if (instance2 != null)
					{
						instance2.AddTextToChatOnServer("<color=red>" + val.playerUsername + "因怯战已被审判犬追猎</color>", -1);
					}
					value2.PendingAnnounced = true;
				}
				if (!TryExecutePlayerByJudgeDog(val))
				{
					KillPlayerDirectlyForExecution(val);
				}
				value2.AttemptCount++;
				value2.NextRetryAt = now + Mathf.Max(1f, PublicFeatureConfig.CurfewRepeatInterval.Value);
			}
		}

		private static bool TryExecutePlayerByJudgeDog(PlayerControllerB activePlayer)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)activePlayer == (Object)null || activePlayer.isPlayerDead)
			{
				return false;
			}
			MouthDogAI orCreateJudgeDog = GetOrCreateJudgeDog();
			if ((Object)(object)orCreateJudgeDog == (Object)null)
			{
				return false;
			}
			Vector3 val = ((Component)activePlayer).transform.position + ((Component)activePlayer).transform.forward * -1.5f;
			((EnemyAI)orCreateJudgeDog).EnableEnemyMesh(true, false, false);
			((Component)orCreateJudgeDog).transform.position = val;
			((EnemyAI)orCreateJudgeDog).serverPosition = val;
			((Component)orCreateJudgeDog).transform.LookAt(((Component)activePlayer).transform.position);
			((EnemyAI)orCreateJudgeDog).SyncPositionToClients();
			activePlayer.inAnimationWithEnemy = (EnemyAI)(object)orCreateJudgeDog;
			orCreateJudgeDog.KillPlayerServerRpc((int)activePlayer.playerClientId);
			int executionSerial = ++_judgeDogExecutionSerial;
			BaseUnityPlugin pluginInstance = PublicFeatureRuntime.PluginInstance;
			if (pluginInstance != null)
			{
				((MonoBehaviour)pluginInstance).StartCoroutine(MoveJudgeDogBackAfterExecution(orCreateJudgeDog, activePlayer, executionSerial));
			}
			return true;
		}

		private static MouthDogAI GetOrCreateJudgeDog()
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_judgeDog != (Object)null && !((EnemyAI)_judgeDog).isEnemyDead)
			{
				return _judgeDog;
			}
			MouthDogAI[] array = Object.FindObjectsOfType<MouthDogAI>();
			foreach (MouthDogAI val in array)
			{
				if ((Object)(object)val != (Object)null && ((Object)((Component)val).gameObject).name.Contains("PublicJudgeDog") && !((EnemyAI)val).isEnemyDead)
				{
					_judgeDog = val;
					return _judgeDog;
				}
			}
			EnemyType val2 = FindMouthDogType();
			if ((Object)(object)val2 == (Object)null || (Object)(object)val2.enemyPrefab == (Object)null)
			{
				return null;
			}
			GameObject obj = Object.Instantiate<GameObject>(val2.enemyPrefab, JudgeDogHiddenPosition, Quaternion.identity);
			((Object)obj).name = "PublicJudgeDog";
			NetworkObject componentInChildren = obj.GetComponentInChildren<NetworkObject>();
			if ((Object)(object)componentInChildren != (Object)null && !componentInChildren.IsSpawned)
			{
				componentInChildren.Spawn(true);
			}
			_judgeDog = obj.GetComponent<MouthDogAI>();
			if ((Object)(object)_judgeDog != (Object)null)
			{
				((EnemyAI)_judgeDog).isOutside = true;
				if ((Object)(object)((EnemyAI)_judgeDog).agent != (Object)null)
				{
					((Behaviour)((EnemyAI)_judgeDog).agent).enabled = false;
				}
				((EnemyAI)_judgeDog).EnableEnemyMesh(false, false, false);
				((EnemyAI)_judgeDog).SwitchToBehaviourState(0);
			}
			return _judgeDog;
		}

		private static EnemyType FindMouthDogType()
		{
			EnemyType val = PublicFeatureEnemyCatalog.GetEnemyTypeByName("MouthDog");
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			RoundManager instance = RoundManager.Instance;
			if ((Object)(object)instance?.currentLevel == (Object)null)
			{
				return null;
			}
			if (instance.currentLevel.OutsideEnemies != null)
			{
				val = instance.currentLevel.OutsideEnemies.Select((SpawnableEnemyWithRarity e) => e.enemyType).FirstOrDefault((Func<EnemyType, bool>)((EnemyType t) => (Object)(object)t != (Object)null && t.enemyName.IndexOf("Dog", StringComparison.OrdinalIgnoreCase) >= 0));
			}
			if ((Object)(object)val == (Object)null && instance.currentLevel.DaytimeEnemies != null)
			{
				val = instance.currentLevel.DaytimeEnemies.Select((SpawnableEnemyWithRarity e) => e.enemyType).FirstOrDefault((Func<EnemyType, bool>)((EnemyType t) => (Object)(object)t != (Object)null && t.enemyName.IndexOf("Dog", StringComparison.OrdinalIgnoreCase) >= 0));
			}
			return val;
		}

		private static IEnumerator MoveJudgeDogBackAfterExecution(MouthDogAI dog, PlayerControllerB target, int executionSerial)
		{
			float startTime = Time.timeSinceLevelLoad;
			yield return (object)new WaitUntil((Func<bool>)(() => (Object)(object)target == (Object)null || (Object)(object)target.deadBody != (Object)null || Time.timeSinceLevelLoad - startTime > 2f));
			yield return (object)new WaitForSeconds(3f);
			if (executionSerial == _judgeDogExecutionSerial && (Object)(object)dog != (Object)null && !((EnemyAI)dog).isEnemyDead)
			{
				((EnemyAI)dog).EnableEnemyMesh(false, false, false);
				((EnemyAI)dog).SwitchToBehaviourState(0);
				((Component)dog).transform.position = JudgeDogHiddenPosition;
				((EnemyAI)dog).serverPosition = JudgeDogHiddenPosition;
				((EnemyAI)dog).SyncPositionToClients();
			}
		}

		private static void KillPlayerDirectlyForExecution(PlayerControllerB player)
		{
			//IL_003b: 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_0026: 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)
			if ((Object)(object)player == (Object)null || player.isPlayerDead)
			{
				return;
			}
			try
			{
				if (((NetworkBehaviour)player).IsOwner)
				{
					player.KillPlayer(Vector3.zero, true, (CauseOfDeath)0, 0, default(Vector3), false);
				}
				else
				{
					player.DamagePlayerFromOtherClientServerRpc(1000, Vector3.zero, (int)player.playerClientId);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger = PublicFeatureRuntime.Logger;
				if (logger != null)
				{
					logger.LogWarning((object)("[CurfewExecution] Direct fallback failed for " + player.playerUsername + ": " + ex.Message));
				}
			}
		}

		private static void RemoveStaleCondemnedPlayers()
		{
			List<ulong> list = new List<ulong>();
			foreach (KeyValuePair<ulong, ExecutionTaskState> condemnedPlayer in CondemnedPlayers)
			{
				if ((Object)(object)FindPlayer(condemnedPlayer.Key) == (Object)null)
				{
					list.Add(condemnedPlayer.Key);
				}
			}
			foreach (ulong item in list)
			{
				CondemnedPlayers.Remove(item);
				if (_activeExecutionTarget == item)
				{
					_activeExecutionTarget = null;
				}
			}
		}

		public static bool TryStartRescue(PlayerControllerB targetPlayer)
		{
			if (!PublicFeatureConfig.RescueEnabled.Value || (Object)(object)targetPlayer == (Object)null || !IsRoundValidForRescue())
			{
				return false;
			}
			if (targetPlayer.isPlayerDead || !targetPlayer.isPlayerControlled || targetPlayer.isInHangarShipRoom)
			{
				return false;
			}
			ulong playerClientId = targetPlayer.playerClientId;
			if (RescuedPlayersThisRound.Contains(playerClientId) || IsRescueImmune(playerClientId) || _rescueCoroutine != null)
			{
				return false;
			}
			if ((Object)(object)PublicFeatureRuntime.PluginInstance == (Object)null)
			{
				return false;
			}
			_rescueCoroutine = ((MonoBehaviour)PublicFeatureRuntime.PluginInstance).StartCoroutine(RescueTeleportCoroutine(targetPlayer));
			return true;
		}

		private static IEnumerator RescueTeleportCoroutine(PlayerControllerB targetPlayer)
		{
			ShipTeleporter teleporter = ((IEnumerable<ShipTeleporter>)Object.FindObjectsOfType<ShipTeleporter>()).FirstOrDefault((Func<ShipTeleporter, bool>)((ShipTeleporter teleporterObject) => (Object)(object)teleporterObject != (Object)null && !teleporterObject.isInverseTeleporter));
			if ((Object)(object)teleporter == (Object)null)
			{
				ShowRescueFailure("救援失败:飞船上没有普通传送器。");
				_rescueCoroutine = null;
				yield break;
			}
			if ((Object)(object)teleporter.buttonTrigger == (Object)null || !teleporter.buttonTrigger.interactable)
			{
				ShowRescueFailure("救援失败:传送器正在冷却。");
				_rescueCoroutine = null;
				yield break;
			}
			if ((Object)(object)StartOfRound.Instance?.mapScreen == (Object)null || StartOfRound.Instance.mapScreen.radarTargets == null)
			{
				ShowRescueFailure("救援失败:雷达尚未准备好。");
				_rescueCoroutine = null;
				yield break;
			}
			int num = -1;
			for (int num2 = 0; num2 < StartOfRound.Instance.mapScreen.radarTargets.Count; num2++)
			{
				Transform val = StartOfRound.Instance.mapScreen.radarTargets[num2]?.transform;
				PlayerControllerB val2 = (((Object)(object)val == (Object)null) ? null : ((Component)val).GetComponentInChildren<PlayerControllerB>());
				if ((Object)(object)val2 != (Object)null && val2.playerClientId == targetPlayer.playerClientId)
				{
					num = num2;
					break;
				}
			}
			if (num < 0)
			{
				ShowRescueFailure("救援失败:无法在雷达上定位该玩家。");
				_rescueCoroutine = null;
				yield break;
			}
			if (!TrySetRadarTarget(num))
			{
				ShowRescueFailure("救援失败:雷达目标切换失败。");
				_rescueCoroutine = null;
				yield break;
			}
			yield return (object)new WaitForSeconds(0.3f);
			if (!IsRoundValidForRescue() || (Object)(object)targetPlayer == (Object)null || targetPlayer.isPlayerDead || targetPlayer.isInHangarShipRoom)
			{
				ShowRescueFailure("救援取消:目标状态已改变。");
				_rescueCoroutine = null;
				yield break;
			}
			if (!TryActivateTeleporter(teleporter))
			{
				ShowRescueFailure("救援失败:传送器调用失败。");
				_rescueCoroutine = null;
				yield break;
			}
			yield return (object)new WaitForSeconds(1.5f);
			if (!IsRoundValidForRescue() || (Object)(object)targetPlayer == (Object)null || targetPlayer.isPlayerDead || !targetPlayer.isInHangarShipRoom)
			{
				ShowRescueFailure("救援失败:传送器未能将目标送回飞船。");
				_rescueCoroutine = null;
				yield break;
			}
			ulong playerClientId = targetPlayer.playerClientId;
			RescuedPlayersThisRound.Add(playerClientId);
			RescueImmunityExpiry[playerClientId] = Time.realtimeSinceStartup + Mathf.Max(1f, PublicFeatureConfig.RescueImmunityDuration.Value);
			CondemnedPlayers.Remove(playerClientId);
			if (_activeExecutionTarget == playerClientId)
			{
				_activeExecutionTarget = null;
			}
			HUDManager instance = HUDManager.Instance;
			if (instance != null)
			{
				instance.AddTextToChatOnServer($"<color=cyan>[救援]</color> <color=yellow>{targetPlayer.playerUsername}</color> 已被救回飞船,{PublicFeatureConfig.RescueImmunityDuration.Value:0.#}秒内免处决。", -1);
			}
			_rescueCoroutine = null;
		}

		private static bool TrySetRadarTarget(int targetIndex)
		{
			try
			{
				StartOfRound.Instance.mapScreen.SwitchRadarTargetServerRpc(targetIndex);
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource logger = PublicFeatureRuntime.Logger;
				if (logger != null)
				{
					logger.LogWarning((object)("[Rescue] Radar target selection failed: " + ex.Message));
				}
				return false;
			}
		}

		private static bool TryActivateTeleporter(ShipTeleporter teleporter)
		{
			try
			{
				teleporter.PressTeleportButtonServerRpc();
				return true;
			}
			catch (Exception ex)
			{
				ManualLogSource logger = PublicFeatureRuntime.Logger;
				if (logger != null)
				{
					logger.LogWarning((object)("[Rescue] Teleporter activation failed: " + ex.Message));
				}
				return false;
			}
		}

		private static bool IsRescueImmune(ulong playerId)
		{
			if (!RescueImmunityExpiry.TryGetValue(playerId, out var value))
			{
				return false;
			}
			if (Time.realtimeSinceStartup < value)
			{
				return true;
			}
			RescueImmunityExpiry.Remove(playerId);
			return false;
		}

		private static void ShowRescueFailure(string message)
		{
			HUDManager instance = HUDManager.Instance;
			if (instance != null)
			{
				instance.AddTextToChatOnServer("<color=red>" + message + "</color>", -1);
			}
		}

		private static PlayerControllerB FindPlayer(ulong playerClientId)
		{
			return StartOfRound.Instance?.allPlayerScripts?.FirstOrDefault((Func<PlayerControllerB, bool>)((PlayerControllerB p) => (Object)(object)p != (Object)null && p.playerClientId == playerClientId));
		}

		private static bool IsRoundValidForRescue()
		{
			if (PublicFeatureRuntime.IsEnabled && (Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)RoundManager.Instance != (Object)null && (((NetworkBehaviour)RoundManager.Instance).IsServer || ((NetworkBehaviour)RoundManager.Instance).IsHost) && StartOfRound.Instance.shipHasLanded)
			{
				return !StartOfRound.Instance.inShipPhase;
			}
			return false;
		}

		private static string FormatCurfewDuration(float duration)
		{
			return duration.ToString("0.##", CultureInfo.InvariantCulture);
		}

		private static bool IsRoundValidForCurfew()
		{
			if (!PublicFeatureRuntime.IsEnabled || !PublicFeatureConfig.CurfewEnabled.Value)
			{
				return false;
			}
			if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)RoundManager.Instance == (Object)null)
			{
				return false;
			}
			if (!((NetworkBehaviour)RoundManager.Instance).IsServer && !((NetworkBehaviour)RoundManager.Instance).IsHost)
			{
				return false;
			}
			if (StartOfRound.Instance.inShipPhase || !StartOfRound.Instance.shipHasLanded)
			{
				return false;
			}
			return true;
		}

		private static bool CanWaitForLanding()
		{
			if (!PublicFeatureRuntime.IsEnabled || !PublicFeatureConfig.CurfewEnabled.Value)
			{
				return false;
			}
			if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)RoundManager.Instance == (Object)null)
			{
				return false;
			}
			if (!((NetworkBehaviour)RoundManager.Instance).IsServer && !((NetworkBehaviour)RoundManager.Instance).IsHost)
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(RoundManager))]
	public static class WorldRulePatches
	{
		[HarmonyPatch("SpawnMapObjects")]
		[HarmonyPrefix]
		private static void SpawnMapObjectsPrefix(RoundManager __instance)
		{
			if (!((NetworkBehaviour)__instance).IsHost || !PublicFeatureConfig.DisableHazards.Value || __instance.currentLevel.indoorMapHazards == null)
			{
				return;
			}
			IndoorMapHazard[] indoorMapHazards = __instance.currentLevel.indoorMapHazards;
			foreach (IndoorMapHazard val in indoorMapHazards)
			{
				if (!((Object)(object)val.hazardType == (Object)null) && !((Object)(object)val.hazardType.prefabToSpawn == (Object)null))
				{
					string name = ((Object)val.hazardType.prefabToSpawn).name;
					if (name.Contains("Landmine") || name.Contains("Turret") || name.Contains("Spike"))
					{
						val.numberToSpawn = AnimationCurve.Constant(0f, 1f, 0f);
					}
				}
			}
		}

		[HarmonyPatch("PlotOutEnemiesForNextHour")]
		[HarmonyPrefix]
		private static bool PlotOutEnemiesPrefix(RoundManager __instance)
		{
			if (((NetworkBehaviour)__instance).IsHost)
			{
				return !PublicFeatureConfig.DisableVanillaEnemies.Value;
			}
			return true;
		}

		[HarmonyPatch("SpawnEnemiesOutside")]
		[HarmonyPrefix]
		private static bool SpawnEnemiesOutsidePrefix(RoundManager __instance)
		{
			if (((NetworkBehaviour)__instance).IsHost)
			{
				return !PublicFeatureConfig.DisableVanillaEnemies.Value;
			}
			return true;
		}

		[HarmonyPatch("SpawnDaytimeEnemiesOutside")]
		[HarmonyPrefix]
		private static bool SpawnDaytimeEnemiesOutsidePrefix(RoundManager __instance)
		{
			if (((NetworkBehaviour)__instance).IsHost)
			{
				return !PublicFeatureConfig.DisableVanillaEnemies.Value;
			}
			return true;
		}

		[HarmonyPatch("SpawnScrapInLevel")]
		[HarmonyPrefix]
		private static bool SpawnScrapInLevelPrefix(RoundManager __instance)
		{
			if (((NetworkBehaviour)__instance).IsHost)
			{
				return !PublicFeatureConfig.DisableScrap.Value;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Terminal), "Awake")]
	public static class PublicTerminalPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Terminal __instance)
		{
			if (__instance.groupCredits == 60)
			{
				__instance.groupCredits = PublicFeatureConfig.StartingCredits.Value;
			}
		}
	}
	[HarmonyPatch(typeof(TimeOfDay), "Awake")]
	public static class PublicTimeOfDayPatch
	{
		[HarmonyPostfix]
		private static void Postfix(TimeOfDay __instance)
		{
			if (__instance.quotaVariables != null)
			{
				__instance.quotaVariables.startingCredits = PublicFeatureConfig.StartingCredits.Value;
			}
		}
	}
	[HarmonyPatch(typeof(DoorLock), "LockDoor")]
	public static class PublicDoorLockPatch
	{
		[HarmonyPostfix]
		private static void Postfix(DoorLock __instance)
		{
			if (PublicFeatureConfig.NoLockedDoors.Value && !((Object)(object)RoundManager.Instance == (Object)null) && (((NetworkBehaviour)RoundManager.Instance).IsServer || ((NetworkBehaviour)RoundManager.Instance).IsHost))
			{
				__instance.UnlockDoorServerRpc();
			}
		}
	}
	[HarmonyPatch(typeof(ButlerEnemyAI), "Start")]
	public static class PublicButlerDoorPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ButlerEnemyAI __instance)
		{
			if (PublicFeatureConfig.ButlerInstantOpenDoors.Value)
			{
				((EnemyAI)__instance).openDoorSpeedMultiplier = 100f;
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "DamagePlayerFromOtherClientClientRpc")]
	public static class PublicFriendlyFirePatch
	{
		[HarmonyPrefix]
		private static bool Prefix(PlayerControllerB __instance, int damageAmount, Vector3 hitDirection, int playerWhoHit, int newHealthAmount)
		{
			if (!PublicFeatureConfig.DisableFriendlyMeleeDamage.Value)
			{
				return true;
			}
			if (damageAmount <= 0 || (Object)(object)StartOfRound.Instance == (Object)null || StartOfRound.Instance.allPlayerScripts == null)
			{
				return true;
			}
			CentipedeAI[] array = Object.FindObjectsByType<CentipedeAI>((FindObjectsSortMode)0);
			for (int i = 0; i < array.Length; i++)
			{
				if ((Object)(object)array[i].clingingToPlayer == (Object)(object)__instance)
				{
					return true;
				}
			}
			if (playerWhoHit >= 0 && playerWhoHit < StartOfRound.Instance.allPlayerScripts.Length)
			{
				PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[playerWhoHit];
				if ((Object)(object)val != (Object)null && (Object)(object)val.currentlyHeldObjectServer != (Object)null && (val.currentlyHeldObjectServer is Shovel || val.currentlyHeldObjectServer is KnifeItem))
				{
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(ShotgunItem), "ShootGun")]
	public static class PublicNutcrackerShotgunPatch
	{
		[HarmonyPrefix]
		private static bool Prefix(ShotgunItem __instance, Vector3 shotgunPosition, Vector3 shotgunForward, ref RaycastHit[] ___enemyColliders, EnemyAI ___heldByEnemy)
		{
			//IL_001a: 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)
			if (!PublicFeatureConfig.NutcrackerNoFriendlyFire.Value)
			{
				return true;
			}
			if (!(___heldByEnemy is NutcrackerEnemyAI))
			{
				return true;
			}
			RunNutcrackerShotgunWithoutMonsterDamage(__instance, shotgunPosition, shotgunForward);
			return false;
		}

		private static void RunNutcrackerShotgunWithoutMonsterDamage(ShotgunItem shotgun, Vector3 shotgunPosition, Vector3 shotgunForward)
		{
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: 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_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			shotgun.isReloading = false;
			bool flag = ((GrabbableObject)shotgun).isHeld && (Object)(object)((GrabbableObject)shotgun).playerHeldBy != (Object)null && (Object)(object)((GrabbableObject)shotgun).playerHeldBy == (Object)(object)GameNetworkManager.Instance.localPlayerController;
			if (flag)
			{
				((GrabbableObject)shotgun).playerHeldBy.playerBodyAnimator.SetTrigger("ShootShotgun");
			}
			RoundManager.PlayRandomClip(shotgun.gunShootAudio, shotgun.gunShootSFX, true, 1f, 1840, 1000);
			WalkieTalkie.TransmitOneShotAudio(shotgun.gunShootAudio, shotgun.gunShootSFX[0], 1f);
			shotgun.gunShootParticle.Play(true);
			shotgun.shellsLoaded = Mathf.Clamp(shotgun.shellsLoaded - 1, 0, 2);
			PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController;
			if (!((Object)(object)localPlayerController == (Object)null))
			{
				float num = Vector3.Distance(((Component)localPlayerController).transform.position, ((Component)shotgun.shotgunRayPoint).transform.position);
				bool flag2 = false;
				int num2 = 0;
				float num3 = 0f;
				Vector3 val = localPlayerController.playerCollider.ClosestPoint(shotgunPosition);
				if (!flag && !Physics.Linecast(shotgunPosition, val, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1) && Vector3.Angle(shotgunForward, val - shotgunPosition) < 30f)
				{
					flag2 = true;
				}
				if (num < 5f)
				{
					num3 = 0.8f;
					HUDManager.Instance.ShakeCamera((ScreenShakeType)1);
					num2 = 100;
				}
				if (num < 15f)
				{
					num3 = 0.5f;
					HUDManager.Instance.ShakeCamera((ScreenShakeType)1);
					num2 = 100;
				}
				else if (num < 23f)
				{
					HUDManager.Instance.ShakeCamera((ScreenShakeType)0);
					num2 = 40;
				}
				else if (num < 30f)
				{
					num2 = 20;
				}
				if (num3 > 0f && SoundManager.Instance.timeSinceEarsStartedRinging > 16f)
				{
					((MonoBehaviour)shotgun).StartCoroutine(DelayedEarsRinging(num3));
				}
				Ray val2 = default(Ray);
				((Ray)(ref val2))..ctor(shotgunPosition, shotgunForward);
				RaycastHit val3 = default(RaycastHit);
				if (Physics.Raycast(val2, ref val3, 30f, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1))
				{
					((Component)shotgun.gunBulletsRicochetAudio).transform.position = ((Ray)(ref val2)).GetPoint(((RaycastHit)(ref val3)).distance - 0.5f);
					shotgun.gunBulletsRicochetAudio.Play();
				}
				if (flag2)
				{
					localPlayerController.DamagePlayer(num2, true, true, (CauseOfDeath)7, 0, false, shotgun.shotgunRayPoint.forward * 30f);
				}
			}
		}

		private static IEnumerator DelayedEarsRinging(float effectSeverity)
		{
			yield return (object)new WaitForSeconds(0.6f);
			SoundManager.Instance.earsRingingTimer = effectSeverity;
		}
	}
	public static class ItemAndLootPatches
	{
		private static class HoarderBugItemCacheCleaner
		{
			public static void CleanupHoarderBugItemCaches()
			{
				if (HoarderBugAI.HoarderBugItems != null)
				{
					HoarderBugAI.HoarderBugItems.RemoveAll((HoarderBugItem item) => item == null || (Object)(object)item.itemGrabbableObject == (Object)null || (Object)(object)((Component)item.itemGrabbableObject).gameObject == (Object)null || item.itemGrabbableObject.deactivated || item.itemGrabbableObject.itemUsedUp);
				}
				if (HoarderBugAI.grabbableObjectsInMap != null)
				{
					HoarderBugAI.grabbableObjectsInMap.RemoveAll((GameObject obj) => (Object)(object)obj == (Object)null);
				}
				CleanupLiveHoarderBugReferences(null);
			}

			public static void RemoveHoarderBugItem(GrabbableObject grabbable)
			{
				if ((Object)(object)grabbable == (Object)null)
				{
					return;
				}
				if (HoarderBugAI.HoarderBugItems != null)
				{
					HoarderBugAI.HoarderBugItems.RemoveAll((HoarderBugItem item) => item == null || (Object)(object)item.itemGrabbableObject == (Object)null || (Object)(object)item.itemGrabbableObject == (Object)(object)grabbable);
				}
				if (HoarderBugAI.grabbableObjectsInMap != null)
				{
					GameObject grabbableObject = ((Component)grabbable).gameObject;
					HoarderBugAI.grabbableObjectsInMap.RemoveAll((GameObject obj) => (Object)(object)obj == (Object)null || (Object)(object)obj == (Object)(object)grabbableObject);
				}
				CleanupLiveHoarderBugReferences(grabbable);
			}

			private static void CleanupLiveHoarderBugReferences(GrabbableObject grabbable)
			{
				HoarderBugAI[] array = Object.FindObjectsByType<HoarderBugAI>((FindObjectsSortMode)0);
				foreach (HoarderBugAI val in array)
				{
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					if ((Object)(object)val.targetItem == (Object)null || (Object)(object)val.targetItem == (Object)(object)grabbable)
					{
						val.targetItem = null;
					}
					if (val.heldItem != null)
					{
						GrabbableObject itemGrabbableObject = val.heldItem.itemGrabbableObject;
						if ((Object)(object)itemGrabbableObject == (Object)null || (Object)(object)itemGrabbableObject == (Object)(object)grabbable)
						{
							val.heldItem = null;
						}
					}
				}
			}
		}

		[HarmonyPatch(typeof(HoarderBugAI), "DoAIInterval")]
		private static class HoarderBugStaleItemCleanupPatch
		{
			[HarmonyPrefix]
			private static void Prefix()
			{
				HoarderBugItemCacheCleaner.CleanupHoarderBugItemCaches();
			}
		}

		[HarmonyPatch(typeof(GrabbableObject), "OnDestroy")]
		private static class HoarderBugDestroyedItemCleanupPatch
		{
			[HarmonyPrefix]
			private static void Prefix(GrabbableObject __instance)
			{
				HoarderBugItemCacheCleaner.RemoveHoarderBugItem(__instance);
			}
		}

		[HarmonyPatch(typeof(NutcrackerEnemyAI), "DropGun")]
		private static class NutcrackerDropGunPatch
		{
			[HarmonyPrefix]
			private static bool Prefix(NutcrackerEnemyAI __instance)
			{
				if (PublicFeatureConfig.NutcrackerDropGunAndShells.Value)
				{
					return true;
				}
				if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.gun == (Object)null)
				{
					return false;
				}
				ShotgunItem gun = __instance.gun;
				__instance.gun = null;
				if (((NetworkBehaviour)__instance).IsServer || ((NetworkBehaviour)__instance).IsHost)
				{
					if ((Object)(object)((NetworkBehaviour)gun).NetworkObject != (Object)null && ((NetworkBehaviour)gun).NetworkObject.IsSpawned)
					{
						((NetworkBehaviour)gun).NetworkObject.Despawn(true);
					}
					else if ((Object)(object)((Component)gun).gameObject != (Object)null)
					{
						Object.Destroy((Object)(object)((Component)gun).gameObject);
					}
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(NutcrackerEnemyAI), "SpawnShotgunShells")]
		private static class NutcrackerShellDropPatch
		{
			[HarmonyPrefix]
			private static bool Prefix()
			{
				return PublicFeatureConfig.NutcrackerDropGunAndShells.Value;
			}
		}

		[HarmonyPatch(typeof(ButlerEnemyAI), "ButlerBlowUpAndPop")]
		private static class ButlerDeathDropPatch
		{
			[HarmonyPrefix]
			private static bool Prefix(ButlerEnemyAI __instance, ref IEnumerator __result)
			{
				if (PublicFeatureConfig.ButlerDropKnifeAndBees.Value)
				{
					return true;
				}
				__result = ButlerBlowUpWithoutDrops(__instance);
				return false;
			}

			private static IEnumerator ButlerBlowUpWithoutDrops(ButlerEnemyAI instance)
			{
				((EnemyAI)instance).creatureAnimator.SetTrigger("Popping");
				((EnemyAI)instance).creatureAnimator.SetLayerWeight(1, 0f);
				instance.popAudio.PlayOneShot(((EnemyAI)instance).enemyType.audioClips[3]);
				yield return (object)new WaitForSeconds(1.1f);
				((EnemyAI)instance).creatureAnimator.SetBool("popFinish", true);
				instance.popAudio.Play();
				instance.popAudioFar.Play();
				instance.popParticle.Play(true);
				float num = Vector3.Distance(((Component)GameNetworkManager.Instance.localPlayerController).transform.position, ((Component)instance).transform.position);
				if (num < 8f)
				{
					Landmine.SpawnExplosion(((Component)instance).transform.position + Vector3.up * 0.15f, false, 0f, 2f, 30, 80f, (GameObject)null, false);
					HUDManager.Instance.ShakeCamera((ScreenShakeType)1);
					SoundManager.Instance.earsRingingTimer = 0.8f;
				}
				else if (num < 27f)
				{
					HUDManager.Instance.ShakeCamera((ScreenShakeType)1);
				}
			}
		}

		[HarmonyPatch(typeof(SandSpiderAI), "KillEnemy")]
		private static class SandSpiderWebCleanupPatch
		{
			[HarmonyPostfix]
			private static void Postfix(SandSpiderAI __instance)
			{
				if ((Object)(object)__instance == (Object)null || (!((NetworkBehaviour)__instance).IsServer && !((NetworkBehaviour)__instance).IsHost))
				{
					return;
				}
				try
				{
					for (int num = __instance.webTraps.Count - 1; num >= 0; num--)
					{
						__instance.BreakWebServerRpc(num, 1);
					}
				}
				catch (Exception arg)
				{
					PublicFeatureRuntime.Logger.LogWarning((object)$"[SandSpider] Failed to clear webs on death: {arg}");
				}
			}
		}

		[HarmonyPatch(typeof(EnemyAI), "KillEnemy")]
		private static class EnemyKillDropPatch
		{
			[HarmonyPostfix]
			private static void Postfix(EnemyAI __instance, bool destroy)
			{
				//IL_0085: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance == (Object)null)
				{
					return;
				}
				if (!destroy)
				{
					TryScheduleCorpseCleanup(__instance);
				}
				if (!destroy && PublicFeatureConfig.LootDropsEnabled.Value && !((Object)(object)RoundManager.Instance == (Object)null) && ((NetworkBehaviour)RoundManager.Instance).IsServer && !((Object)(object)__instance.enemyType == (Object)null) && SupportsCombatDrops(__instance) && !PublicFeatureRuntime.IsPrivateBossEnemy(__instance))
				{
					EnsureLootItemsCached();
					if ((Object)(object)_tzpItem != (Object)null && Random.value <= PublicFeatureConfig.TZPDropChance.Value)
					{
						SpawnLoot(((Component)__instance).transform.position, _tzpItem);
					}
					if ((Object)(object)_stunGrenadeItem != (Object)null && Random.value <= PublicFeatureConfig.StunGrenadeDropChance.Value)
					{
						SpawnLoot(((Component)__instance).transform.position, _stunGrenadeItem);
					}
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "DamagePlayerClientRpc")]
		private static class PlayerDamageSyncPatch
		{
			[HarmonyPostfix]
			private static void Postfix(PlayerControllerB __instance, int newHealthAmount)
			{
				if (((NetworkBehaviour)__instance).IsOwner && newHealthAmount >= 20 && __instance.criticallyInjured)
				{
					__instance.criticallyInjured = false;
					if ((Object)(object)__instance.playerBodyAnimator != (Object)null)
					{
						__instance.playerBodyAnimator.SetBool("Limp", false);
					}
					__instance.bleedingHeavily = false;
				}
			}
		}

		[HarmonyPatch(typeof(TetraChemicalItem), "Update")]
		private static class TZPHealingPatch
		{
			[HarmonyPostfix]
			private static void Postfix(TetraChemicalItem __instance)
			{
				if ((Object)(object)__instance == (Object)null || (Object)(object)((NetworkBehaviour)__instance).NetworkObject == (Object)null || !PublicFeatureConfig.TZPHealingEnabled.Value || (Object)(object)((NetworkBehaviour)__instance).NetworkManager == (Object)null || !((NetworkBehaviour)__instance).NetworkManager.IsServer)
				{
					return;
				}
				if (UsedTZPIndices.Contains(((NetworkBehaviour)__instance).NetworkObjectId))
				{
					ulong networkObjectId = ((NetworkBehaviour)__instance).NetworkObjectId;
					if ((Object)(object)((GrabbableObject)__instance).playerHeldBy == (Object)null)
					{
						if (!UsedTZPOnGroundSince.TryGetValue(networkObjectId, out var value))
						{
							UsedTZPOnGroundSince[networkObjectId] = Time.time;
						}
						else if (Time.time - value > 2f)
						{
							UsedTZPOnGroundSince.Remove(networkObjectId);
							if (((NetworkBehaviour)__instance).NetworkObject.IsSpawned)
							{
								((NetworkBehaviour)__instance).NetworkObject.Despawn(true);
							}
						}
					}
					else
					{
						UsedTZPOnGroundSince.Remove(networkObjectId);
					}
				}
				else
				{
					if (!(bool)AccessTools.Field(typeof(TetraChemicalItem), "emittingGas").GetValue(__instance) || (Object)(object)((GrabbableObject)__instance).playerHeldBy == (Object)null)
					{
						return;
					}
					PlayerControllerB playerHeldBy = ((GrabbableObject)__instance).playerHeldBy;
					if (!playerHeldBy.isPlayerDead)
					{
						HealPlayerFromTzpNetworked(playerHeldBy, PublicFeatureConfig.TZPHealAmount.Value);
						if (playerHeldBy.criticallyInjured)
						{
							playerHeldBy.MakeCriticallyInjured(false);
						}
						UsedTZPIndices.Add(((NetworkBehaviour)__instance).NetworkObjectId);
					}
				}
			}
		}

		private static readonly HashSet<ulong> UsedTZPIndices = new HashSet<ulong>();

		private static readonly Dictionary<ulong, float> UsedTZPOnGroundSince = new Dictionary<ulong, float>();

		private static readonly Dictionary<ulong, int> PendingTzpCriticalHealTargets = new Dictionary<ulong, int>();

		private static readonly Dictionary<ulong, Coroutine> PendingTzpCriticalHealCoroutines = new Dictionary<ulong, Coroutine>();

		private static Item _tzpItem;

		private static Item _stunGrenadeItem;

		public static void ResetRoundState()
		{
			UsedTZPIndices.Clear();
			UsedTZPOnGroundSince.Clear();
			PendingTzpCriticalHealTargets.Clear();
			foreach (Coroutine value in PendingTzpCriticalHealCoroutines.Values)
			{
				if (value != null && (Object)(object)PublicFeatureRuntime.PluginInstance != (Object)null)
				{
					((MonoBehaviour)PublicFeatureRuntime.PluginInstance).StopCoroutine(value);
				}
			}
			PendingTzpCriticalHealCoroutines.Clear();
			_tzpItem = null;
			_stunGrenadeItem = null;
		}

		private static void EnsureLootItemsCached()
		{
			if (((Object)(object)_tzpItem != (Object)null && (Object)(object)_stunGrenadeItem != (Object)null) || (Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)StartOfRound.Instance.allItemsList == (Object)null)
			{
				return;
			}
			foreach (Item items in StartOfRound.Instance.allItemsList.itemsList)
			{
				if ((Object)(object)_tzpItem == (Object)null && items.itemName == "TZP-Inhalant")
				{
					_tzpItem = items;
				}
				else if ((Object)(object)_stunGrenadeItem == (Object)null && items.itemName == "Stun grenade")
				{
					_stunGrenadeItem = items;
				}
			}
		}

		private static bool SupportsCombatDrops(EnemyAI enemy)
		{
			if (!(enemy is FlowermanAI) && !(enemy is ButlerEnemyAI) && !(enemy is NutcrackerEnemyAI) && !(enemy is MaskedPlayerEnemy) && !(enemy is SandSpiderAI) && !(enemy is CentipedeAI) && !(enemy is CrawlerAI) && !(enemy is HoarderBugAI) && !(enemy is BaboonBirdAI) && !(enemy is StingrayAI) && !(enemy is CaveDwellerAI))
			{
				return enemy is GiantKiwiAI;
			}
			return true;
		}

		private static bool SupportsCorpseCleanup(EnemyAI enemy)
		{
			if (!(enemy is FlowermanAI) && !(enemy is ButlerEnemyAI) && !(enemy is NutcrackerEnemyAI) && !(enemy is MaskedPlayerEnemy) && !(enemy is SandSpiderAI) && !(enemy is CentipedeAI) && !(enemy is CrawlerAI) && !(enemy is HoarderBugAI) && !(enemy is BaboonBirdAI) && !(enemy is StingrayAI) && !(enemy is CaveDwellerAI))
			{
				return enemy is GiantKiwiAI;
			}
			return true;
		}

		private static void TryScheduleCorpseCleanup(EnemyAI enemy)
		{
			if (!PublicFeatureConfig.CorpseCleanupEnabled.Value || (Object)(object)enemy == (Object)null || !SupportsCorpseCleanup(enemy) || PublicFeatureRuntime.IsPrivateBossEnemy(enemy) || (!((NetworkBehaviour)enemy).IsServer && !((NetworkBehaviour)enemy).IsHost))
			{
				return;
			}
			try
			{
				if (Traverse.Create((object)enemy).Field<Coroutine>("deathCoroutine").Value == null)
				{
					float delay = Mathf.Max(0f, PublicFeatureConfig.CorpseCleanupDelay.Value);
					Coroutine value = ((MonoBehaviour)enemy).StartCoroutine(CorpseCleanupCoroutine(enemy, delay));
					Traverse.Create((object)enemy).Field("deathCoroutine").SetValue((object)value);
				}
			}
			catch (Exception arg)
			{
				PublicFeatureRuntime.Logger.LogError((object)$"[CorpseCleanup] Failed to schedule cleanup for {enemy.enemyType?.enemyName ?? ((Object)enemy).name}: {arg}");
			}
		}

		private static IEnumerator CorpseCleanupCoroutine(EnemyAI enemy, float delay)
		{
			yield return (object)new WaitForSeconds(delay);
			if (!((Object)(object)enemy == (Object)null))
			{
				if ((Object)(object)((NetworkBehaviour)enemy).NetworkObject != (Object)null && ((NetworkBehaviour)enemy).NetworkObject.IsSpawned && (((NetworkBehaviour)enemy).IsServer || ((NetworkBehaviour)enemy).IsHost))
				{
					((NetworkBehaviour)enemy).NetworkObject.Despawn(true);
				}
				else if ((Object)(object)((Component)enemy).gameObject != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)enemy).gameObject);
				}
			}
		}

		private static void SpawnLoot(Vector3 position, Item item)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0038: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null || (Object)(object)item.spawnPrefab == (Object)null)
			{
				return;
			}
			try
			{
				Vector3 val = position + Vector3.up * 0.5f + Random.insideUnitSphere * 0.2f;
				GameObject val2 = Object.Instantiate<GameObject>(item.spawnPrefab, val, Random.rotation);
				GrabbableObject component = val2.GetComponent<GrabbableObject>();
				if ((Object)(object)component != (Object)null)
				{
					component.startFallingPosition = val;
					component.FallToGround(true, true, default(Vector3));
					NetworkObject component2 = val2.GetComponent<NetworkObject>();
					if ((Object)(object)component2 != (Object)null)
					{
						component2.Spawn(true);
					}
				}
			}
			catch (Exception arg)
			{
				PublicFeatureRuntime.Logger.LogError((object)$"[LootDrops] Failed to spawn {item.itemName}: {arg}");
			}
		}

		private static void HealPlayerFromTzpNetworked(PlayerControllerB player, int amount)
		{
			if ((Object)(object)player == (Object)null || player.isPlayerDead || amount <= 0)
			{
				return;
			}
			ulong playerClientId = player.playerClientId;
			if (PendingTzpCriticalHealTargets.TryGetValue(playerClientId, out var value))
			{
				int num = Mathf.Clamp(Mathf.Max(player.health, value) + amount, 20, 100);
				if (num > value)
				{
					PendingTzpCriticalHealTargets[playerClientId] = num;
				}
				return;
			}
			int health = player.health;
			int num2 = Mathf.Clamp(health + amount, 0, 100);
			if (num2 <= health)
			{
				return;
			}
			if (player.health > 0 && (player.health < 20 || player.criticallyInjured) && num2 >= 20)
			{
				if (player.health < 19)
				{
					player.DamagePlayerClientRpc(-(19 - player.health), 19);
				}
				else if (player.health != 19)
				{
					player.DamagePlayerClientRpc(0, 19);
				}
				SchedulePendingTzpCriticalHeal(player, num2);
			}
			else
			{
				player.DamagePlayerClientRpc(-(num2 - player.health), num2);
			}
		}

		private static void SchedulePendingTzpCriticalHeal(PlayerControllerB player, int finalHealth)
		{
			if (!((Object)(object)player == (Object)null) && !player.isPlayerDead && !((Object)(object)PublicFeatureRuntime.PluginInstance == (Object)null))
			{
				ulong playerClientId = player.playerClientId;
				PendingTzpCriticalHealTargets[playerClientId] = finalHealth;
				if (!PendingTzpCriticalHealCoroutines.TryGetValue(playerClientId, out var value) || value == null)
				{
					PendingTzpCriticalHealCoroutines[playerClientId] = ((MonoBehaviour)PublicFeatureRuntime.PluginInstance).StartCoroutine(ApplyPendingTzpCriticalHeal(player, playerClientId));
				}
			}
		}

		private static IEnumerator ApplyPendingTzpCriticalHeal(PlayerControllerB player, ulong playerId)
		{
			yield return (object)new WaitForSeconds(1.25f);
			PendingTzpCriticalHealCoroutines.Remove(playerId);
			if (!PendingTzpCriticalHealTargets.TryGetValue(playerId, out var value))
			{
				yield break;
			}
			PendingTzpCriticalHealTargets.Remove(playerId);
			if ((Object)(object)player == (Object)null || player.isPlayerDead || player.health < 19 || player.health > 20)
			{
				yield break;
			}
			value = Mathf.Clamp(value, 20, 100);
			if (value <= player.health)
			{
				if (player.health >= 20)
				{
					player.DamagePlayerClientRpc(0, player.health);
				}
			}
			else
			{
				player.DamagePlayerClientRpc(-(value - player.health), value);
			}
		}
	}
	public static class CombatScoreboardSystem
	{
		private sealed class PlayerScoreState
		{
			internal ulong PlayerId;

			internal string PlayerName;

			internal int Hits;

			internal int KillScore;
		}

		public sealed class PlayerScoreSnapshot
		{
			public PlayerControllerB Player { get; private set; }

			public string PlayerName { get; private set; }

			public int Hits { get; private set; }

			public int KillScore { get; private set; }

			public float TotalScore { get; private set; }

			internal PlayerScoreSnapshot(PlayerControllerB player, string playerName, int hits, int killScore, float totalScore)
			{
				Player = player;
				PlayerName = playerName;
				Hits = hits;
				KillScore = killScore;
				TotalScore = totalScore;
			}
		}

		private const int WindowId = 41982;

		private static readonly Dictionary<ulong, PlayerScoreState> PlayerScores = new Dictionary<ulong, PlayerScoreState>();

		private static readonly Dictionary<ulong, ulong> LastHitters = new Dictionary<ulong, ulong>();

		private static readonly HashSet<ulong> ProcessedKills = new HashSet<ulong>();

		private static Coroutine _broadcastCoroutine;

		private static Coroutine _mvpAnnouncementCoroutine;

		private static CombatScoreboardBehaviour _behaviour;

		private static bool _windowVisible;

		private static bool _gameOverMvpAnnounced;

		private static bool _gameOverMvpPending;

		private static Rect _windowRect = new Rect(12f, 12f, 580f, 160f);

		public static void Initialize()
		{
			if (!((Object)(object)PublicFeatureRuntime.PluginInstance == (Object)null) && (Object)(object)_behaviour == (Object)null)
			{
				_behaviour = ((Component)PublicFeatureRuntime.PluginInstance).gameObject.GetComponent<CombatScoreboardBehaviour>();
				if ((Object)(object)_behaviour == (Object)null)
				{
					_behaviour = ((Component)PublicFeatureRuntime.PluginInstance).gameObject.AddComponent<CombatScoreboardBehaviour>();
				}
			}
		}

		public static void ResetRoundState()
		{
			PlayerScores.Clear();
			LastHitters.Clear();
			ProcessedKills.Clear();
			_windowVisible = false;
			_gameOverMvpAnnounced = false;
			_gameOverMvpPending = false;
			if (_mvpAnnouncementCoroutine != null && (Object)(object)PublicFeatureRuntime.PluginInstance != (Object)null)
			{
				((MonoBehaviour)PublicFeatureRuntime.PluginInstance).StopCoroutine(_mvpAnnouncementCoroutine);
			}
			_mvpAnnouncementCoroutine = null;
			SeedControlledPlayers();
		}

		private static void SeedControlledPlayers()
		{
			PlayerControllerB[] array = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.allPlayerScripts : null);
			if (array == null)
			{
				return;
			}
			PlayerControllerB[] array2 = array;
			foreach (PlayerControllerB val in array2)
			{
				if ((Object)(object)val != (Object)null && val.isPlayerControlled)
				{
					GetOrCreatePlayerState(val);
				}
			}
		}

		public static void StartBroadcast()
		{
			StopBroadcast();
			if ((Object)(object)PublicFeatureRuntime.PluginInstance != (Object)null && PublicFeatureConfig.ScoreboardEnabled.Value && PublicFeatureConfig.ScoreboardBroadcastEnabled.Value)
			{
				_broadcastCoroutine = ((MonoBehaviour)PublicFeatureRuntime.PluginInstance).StartCoroutine(BroadcastRoutine());
			}
		}

		public static void Stop()
		{
			StopBroadcast();
			ResetRoundState();
		}

		public static void RestartBroadcast()
		{
			StartBroadcast();
		}

		public static void EndRound()
		{
			StopBroadcast();
			_windowVisible = false;
		}

		public static void ScheduleMvpAnnouncement()
		{
			ManualLogSource logger = PublicFeatureRuntime.Logger;
			if (logger != null)
			{
				logger.LogInfo((object)"[MVP] Game-over hook triggered.");
			}
			if (_gameOverMvpAnnounced || _gameOverMvpPending)
			{
				ManualLogSource logger2 = PublicFeatureRuntime.Logger;
				if (logger2 != null)
				{
					logger2.LogInfo((object)"[MVP] Skipped because an announcement is already pending or sent.");
				}
				return;
			}
			if (!IsServer() || !PublicFeatureConfig.ScoreboardEnabled.Value || !PublicFeatureConfig.MvpEnabled.Value)
			{
				ManualLogSource logger3 = PublicFeatureRuntime.Logger;
				if (logger3 != null)
				{
					logger3.LogInfo((object)"[MVP] Skipped because this instance is not the server or MVP is disabled.");
				}
				return;
			}
			PlayerScoreSnapshot playerScoreSnapshot = CaptureMvpSnapshot();
			if (playerScoreSnapshot == null)
			{
				ManualLogSource logger4 = PublicFeatureRuntime.Logger;
				if (logger4 != null)
				{
					logger4.LogWarning((object)$"[MVP] No player score snapshot was available. Stored score entries: {PlayerScores.Count}.");
				}
				return;
			}
			if ((Object)(object)PublicFeatureRuntime.PluginInstance == (Object)null)
			{
				ManualLogSource logger5 = PublicFeatureRuntime.Logger;
				if (logger5 != null)
				{
					logger5.LogWarning((object)"[MVP] Plugin instance is unavailable; cannot start delayed announcement.");
				}
				return;
			}
			_gameOverMvpPending = true;
			ManualLogSource logger6 = PublicFeatureRuntime.Logger;
			if (logger6 != null)
			{
				logger6.LogInfo((object)$"[MVP] Snapshot captured for {playerScoreSnapshot.PlayerName}: hits={playerScoreSnapshot.Hits}, score={playerScoreSnapshot.KillScore}, total={playerScoreSnapshot.TotalScore:0.0}.");
			}
			_mvpAnnouncementCoroutine = ((MonoBehaviour)PublicFeatureRuntime.PluginInstance).StartCoroutine(DelayedMvpAnnouncement(playerScoreSnapshot));
		}

		private static PlayerScoreSnapshot CaptureMvpSnapshot()
		{
			if (PlayerScores.Count == 0)
			{
				return null;
			}
			PlayerScoreState playerScoreState = (from state in PlayerScores.Values
				orderby CalculateTotalScore(state.KillScore, state.Hits) descending, state.KillScore descending, state.Hits descending
				select state).ThenBy<PlayerScoreState, string>((PlayerScoreState state) => state.PlayerName ?? string.Empty, StringComparer.OrdinalIgnoreCase).FirstOrDefault();
			if (playerScoreState == null)
			{
				return null;
			}
			return new PlayerScoreSnapshot(FindPlayer(playerScoreState.PlayerId), string.IsNullOrEmpty(playerScoreState.PlayerName) ? "Unknown" : playerScoreState.PlayerName, playerScoreState.Hits, playerScoreState.KillScore, CalculateTotalScore(playerScoreState.KillScore, playerScoreState.Hits));
		}

		private static IEnumerator DelayedMvpAnnouncement(PlayerScoreSnapshot mvp)
		{
			float deadline = Time.realtimeSinceStartup + 12f;
			while (Time.realtimeSinceStartup < deadline && (!((Object)(object)StartOfRound.Instance != (Object)null) || !StartOfRound.Instance.inShipPhase || !((Object)(object)HUDManager.Instance != (Object)null)))
			{
				yield return (object)new WaitForSecondsRealtime(0.5f);
			}
			if ((Object)(object)HUDManager.Instance == (Object)null)
			{
				ManualLogSource logger = PublicFeatureRuntime.Logger;
				if (logger != null)
				{
					logger.LogWarning((object)"[MVP] Announcement timed out because HUDManager was unavailable.");
				}
				_gameOverMvpPending = false;
				_mvpAnnouncementCoroutine = null;
				yield break;
			}
			yield return (object)new WaitForSecondsRealtime(1f);
			HUDManager.Instance.AddTextToChatOnServer("<color=#00FFFF>[本局MVP]</color> <color=#FFD700>" + mvp.PlayerName + "</color> " + $"命中:<color=#FF8C00>{mvp.Hits}</color> " + $"得分:<color=#32CD32>{mvp.KillScore}</color> " + $"总分:<color=#DA70D6>{mvp.TotalScore:0.0}</color>", -1);
			_gameOverMvpAnnounced = true;
			_gameOverMvpPending = false;
			_mvpAnnouncementCoroutine = null;
			ManualLogSource logger2 = PublicFeatureRuntime.Logger;
			if (logger2 != null)
			{
				logger2.LogInfo((object)("[MVP] Announcement sent for " + mvp.PlayerName + "."));
			}
		}

		public static void RecordHit(EnemyAI enemy, PlayerControllerB player)
		{
			if (IsServer() && PublicFeatureConfig.ScoreboardEnabled.Value && !((Object)(object)enemy == (Object)null) && !((Object)(object)player == (Object)null) && !enemy.isEnemyDead && player.isPlayerControlled && !player.isPlayerDead && !((Object)(object)((NetworkBehaviour)enemy).NetworkObject == (Object)null) && ((NetworkBehaviour)enemy).NetworkObject.IsSpawned && GetEnemyScore(enemy) > 0)
			{
				GetOrCreatePlayerState(player).Hits++;
				LastHitters[GetEnemyTrackingId(enemy)] = player.playerClientId;
			}
		}

		public static void RecordKill(EnemyAI enemy)
		{
			if (!IsServer() || !PublicFeatureConfig.ScoreboardEnabled.Value || (Object)(object)enemy == (Object)null || (Object)(object)((NetworkBehaviour)enemy).NetworkObject == (Object)null)
			{
				return;
			}
			ulong enemyTrackingId = GetEnemyTrackingId(enemy);
			if (!ProcessedKills.Add(enemyTrackingId))
			{
				return;
			}
			try
			{
				int enemyScore = GetEnemyScore(enemy);
				if (enemyScore > 0 && LastHitters.TryGetValue(enemyTrackingId, out var value))
				{
					PlayerControllerB val = FindPlayer(value);
					if (!((Object)(object)val == (Object)null) && val.isPlayerControlled)
					{
						GetOrCreatePlayerState(val).KillScore += enemyScore;
					}
				}
			}
			finally
			{
				LastHitters.Remove(enemyTrackingId);
			}
		}

		public static IReadOnlyList<PlayerScoreSnapshot> GetRankedPlayers()
		{
			List<PlayerScoreSnapshot> list = new List<PlayerScoreSnapshot>();
			PlayerControllerB[] array = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.allPlayerScripts : null);
			if (array == null)
			{
				return list;
			}
			PlayerControllerB[] array2 = array;
			foreach (PlayerControllerB val in array2)
			{
				if (!((Object)(object)val == (Object)null) && val.isPlayerControlled)
				{
					PlayerScoreState orCreatePlayerState = GetOrCreatePlayerState(val);
					list.Add(new PlayerScoreSnapshot(val, string.IsNullOrEmpty(val.playerUsername) ? "Unknown" : val.playerUsername, orCreatePlayerState.Hits, orCreatePlayerState.KillScore, CalculateTotalScore(orCreatePlayerState.KillScore, orCreatePlayerState.Hits)));
				}
			}
			return (from snapshot in list
				orderby snapshot.TotalScore descending, snapshot.KillScore descending, snapshot.Hits descending
				select snapshot).ThenBy<PlayerScoreSnapshot, string>((PlayerScoreSnapshot snapshot) => snapshot.PlayerName, StringComparer.OrdinalIgnoreCase).ToList();
		}

		internal static void Update()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (IsServer() && PublicFeatureConfig.ScoreboardEnabled.Value && Keyboard.current != null && ((ButtonControl)Keyboard.current[PublicFeatureConfig.ScoreboardKey.Value]).wasPressedThisFrame)
			{
				_windowVisible = !_windowVisible;
			}
		}

		internal static void OnGui()
		{
			//IL_0020: 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_003b: Expected O, but got Unknown
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (IsServer() && PublicFeatureConfig.ScoreboardEnabled.Value && _windowVisible)
			{
				_windowRect = GUI.Window(41982, _windowRect, new WindowFunction(DrawWindow), string.Empty);
			}
		}

		private static void DrawWindow(int windowId)
		{
			IReadOnlyList<PlayerScoreSnapshot> rankedPlayers = GetRankedPlayers();
			float height = Mathf.Clamp(82f + (float)rankedPlayers.Count * 28f, 120f, (float)Screen.height - 20f);
			((Rect)(ref _windowRect)).height = height;
			((Rect)(ref _windowRect)).x = Mathf.Clamp(((Rect)(ref _windowRect)).x, 10f, Mathf.Max(10f, (float)Screen.width - ((Rect)(ref _windowRect)).width - 10f));
			((Rect)(ref _windowRect)).y = Mathf.Clamp(((Rect)(ref _windowRect)).y, 10f, Mathf.Max(10f, (float)Screen.height - ((Rect)(ref _windowRect)).height - 10f));
			GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
			GUILayout.Label("战斗记分板", Array.Empty<GUILayoutOption>());
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			GUILayout.Label("名次", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(45f) });
			GUILayout.Label("玩家", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) });
			GUILayout.Label("命中", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
			GUILayout.Label("得分", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
			GUILayout.Label("总分", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
			GUILayout.Label("救援", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) });
			GUILayout.EndHorizontal();
			for (int i = 0; i < rankedPlayers.Count; i++)
			{
				PlayerScoreSnapshot playerScoreSnapshot = rankedPlayers[i];
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label((i + 1).ToString(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(45f) });
				GUILayout.Label(playerScoreSnapshot.PlayerName, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(180f) });
				GUILayout.Label(playerScoreSnapshot.Hits.ToString(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
				GUILayout.Label(playerScoreSnapshot.KillScore.ToString(), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
				GUILayout.Label(playerScoreSnapshot.TotalScore.ToString("0.0"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) });
				GUI.enabled = PublicFeatureConfig.RescueEnabled.Value && (Object)(object)playerScoreSnapshot.Player != (Object)null && !playerScoreSnapshot.Player.isPlayerDead && !playerScoreSnapshot.Player.isInHangarShipRoom;
				if (GUILayout.Button("救援", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(70f) }))
				{
					CurfewExecutionSystem.TryStartRescue(playerScoreSnapshot.Player);
				}
				GUI.enabled = true;
				GUILayout.EndHorizontal();
			}
			GUILayout.EndVertical();
			GUI.DragWindow();
		}

		private static IEnumerator BroadcastRoutine()
		{
			while (PublicFeatureRuntime.IsEnabled && PublicFeatureConfig.ScoreboardEnabled.Value && PublicFeatureConfig.ScoreboardBro