Decompiled source of RollOfTheScoutPandora v1.0.0

plugins/com.peakmodding.RollOfTheScoutPandora.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using RollOfTheScout;
using UnityEngine;
using UnityEngine.SceneManagement;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.peakmodding.RollOfTheScoutPandora")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("com.peakmodding.RollOfTheScoutPandora")]
[assembly: AssemblyTitle("RollOfTheScoutPandora")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace RollOfTheScoutPandora
{
	public static class CheckpointPatches
	{
		public static void SetColorPostfix(CheckpointFlag __instance)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				PandoraModeManager.Instance?.OnCheckpointFlagPlanted(__instance);
			}
		}

		public static void OnDisablePostfix(CheckpointFlag __instance)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				PandoraModeManager.Instance?.OnCheckpointFlagRemoved(__instance);
			}
		}

		public static void RegainItemsPostfix(CharacterData __instance, object[] __args)
		{
			if (!PhotonNetwork.IsMasterClient)
			{
				return;
			}
			Character val = null;
			if (__args != null)
			{
				foreach (object obj in __args)
				{
					PhotonView val2 = (PhotonView)((obj is PhotonView) ? obj : null);
					if (val2 != null)
					{
						val = ((Component)val2).GetComponent<Character>();
						if ((Object)(object)val == (Object)null)
						{
							val = ((Component)val2).GetComponentInParent<Character>();
						}
						if ((Object)(object)val != (Object)null)
						{
							break;
						}
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				val = CharacterOf(__instance);
			}
			if (!((Object)(object)val == (Object)null))
			{
				PandoraModeManager.Instance?.OnCheckpointRegain(val);
			}
		}

		public static void DiePostfix(CharacterData __instance)
		{
			if (PhotonNetwork.IsMasterClient)
			{
				Character val = CharacterOf(__instance);
				if (!((Object)(object)val == (Object)null))
				{
					PandoraModeManager.Instance?.OnCharacterDied(val);
				}
			}
		}

		private static Character CharacterOf(CharacterData data)
		{
			if ((Object)(object)data == (Object)null)
			{
				return null;
			}
			Character val = ((Component)data).GetComponent<Character>();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)data).GetComponentInParent<Character>();
			}
			return val;
		}
	}
	public static class PandoraModeConfig
	{
		private const string SectionName = "PandoraBattleRoyale潘多拉大乱斗";

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

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

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

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

		public static ConfigEntry<string> WinnerRewardItem { get; private set; }

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

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

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

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

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

		public static void Initialize(ConfigFile config)
		{
			Enabled = Bind(config, "Enabled启用", defaultValue: false, "Enable the Pandora Battle Royale mode. Default false. Read once when leaving the airport for a run.", "是否启用「潘多拉大乱斗」模式。默认 false;每局仅在离开机场进入关卡时读取一次。");
			PreparationSeconds = Bind(config, "PreparationSeconds准备期时长", 150f, "Preparation time at the start of each level, in seconds. Default 150. All alive players receive invincibility every 10 seconds during this period.", "每关开场的准备期时长(秒)。默认 150;准备期内全体存活玩家每 10 秒获得一次无敌。");
			PandoraEffectRadius = Bind(config, "PandoraEffectRadius潘多拉作用半径", 30f, "Effective radius of Pandora's box effect in this mode, in metres. Default 30. Overrides the main mod value while the mode is active.", "本模式下潘多拉魔盒的作用半径(米)。默认 30;模式激活时覆盖主模组同名配置。");
			TeleportDelaySeconds = Bind(config, "TeleportDelaySeconds传送延迟", 3f, "Delay between the winner being determined and teleporting to the current level's summit campfire / the Peak summit, in seconds. Default 3. The timer restarts if the winner dies and is revived.", "赢家判定后到传送至当前关卡山顶篝火 / 顶峰山顶的延迟(秒)。默认 3;赢家死亡并被复活后重新计时。");
			WinnerRewardItem = Bind(config, "WinnerRewardItem赢家奖励物品", "Flag_Plantable_Checkpoint", "Prefab name of the winner reward item. Default Flag_Plantable_Checkpoint (the vanilla checkpoint flag).", "赢家奖励物品的预制体名。默认 Flag_Plantable_Checkpoint(原版检查点旗标)。");
			WinnerRewardCount = Bind(config, "WinnerRewardCount赢家奖励物品倍数", 1, "How many reward items the winner receives. 0 disables the reward. Default 1.", "赢家获得的奖励物品数量。设为 0 表示不发放。默认 1。");
			AntiIsolationTeleportEnabled = Bind(config, "AntiIsolationTeleportEnabled防孤立传送启用", defaultValue: true, "During the battle (after preparation, before a winner), every 10 s teleport one isolated Pandora's Child to another random Pandora's Child. Default true.", "战斗期间(准备期结束、赢家判定前),每 10 秒把 1 名孤立潘多拉之子传送到随机另一名潘多拉之子处。默认启用。");
			AntiIsolationTeleportRadius = Bind(config, "AntiIsolationTeleportRadius防孤立传送半径", 150f, "Isolation radius for the teleport feature, in metres. A Pandora's Child with no other Pandora's Child inside this radius is considered isolated. Default 150.", "防孤立传送的孤立判定半径(米):半径内没有其他潘多拉之子即视为孤立。默认 150。");
			IsolatedScoutmasterEnabled = Bind(config, "IsolatedScoutmasterEnabled孤立童军领队启用", defaultValue: false, "During the battle, every 15 s spawn a Scoutmaster 10 m outside an isolated Pandora's Child; it chases for 30 s, at most 2 per player. Default false.", "战斗期间每 15 秒在孤立潘多拉之子半径 10 米外生成 1 名童军领队,追击 30 秒;每名玩家同时最多 2 名。默认关闭。");
			IsolatedScoutmasterRadius = Bind(config, "IsolatedScoutmasterRadius孤立童军领队半径", 150f, "Isolation radius for the Scoutmaster feature, in metres. Default 150.", "孤立童军领队的孤立判定半径(米)。默认 150。");
		}

		private static ConfigEntry<T> Bind<T>(ConfigFile config, string key, T defaultValue, string descriptionEnglish, string descriptionChinese)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			return config.Bind<T>("PandoraBattleRoyale潘多拉大乱斗", key, defaultValue, new ConfigDescription(descriptionEnglish + "\n" + descriptionChinese, (AcceptableValueBase)null, Array.Empty<object>()));
		}
	}
	public sealed class PandoraModeManager : MonoBehaviour
	{
		private sealed class FlagRecord
		{
			public PhotonView View;

			public string PlayerId;

			public ClassType ClassAtPlant;

			public bool SkeletonAtPlant;
		}

		private sealed class ScoutmasterLink
		{
			public PhotonView View;

			public string TargetId;

			public float SpawnedAt;

			public float ExpireAt;

			public bool Escaped;
		}

		private const float PrepInvincibleInterval = 10f;

		private const int PandoraMaxPlayersOverride = 99;

		private const float PandoraBoxIntervalOverride = 5f;

		private const float OvertimeGraceSeconds = 1f;

		private const float WinnerReviveGraceSeconds = 0.35f;

		private const float AuthorizedReviveWindow = 2f;

		private const float AntiIsolationTeleportInterval = 10f;

		private const float IsolatedScoutmasterInterval = 15f;

		private const float IsolatedScoutmasterSpawnDistance = 10f;

		private const float IsolatedScoutmasterChaseSeconds = 30f;

		private const int MaxScoutmastersPerPlayer = 2;

		private const float AntiIsolationSafeOffset = 1f;

		private const float AntiIsolationTeleportDetectWindow = 2f;

		private bool _sawAirport;

		private bool _runLatched;

		private bool _runEnabled;

		private bool _modeAborted;

		private bool _modeEnded;

		private int _handledSerial;

		private int _levelIndex;

		private bool _prepActive;

		private float _prepStarted;

		private float _nextInvincible;

		private bool _winnerDetermined;

		private bool _winnerLeft;

		private bool _teleportPending;

		private bool _rewardPending;

		private bool _winnerReviveDone;

		private string _winnerId;

		private float _teleportScheduledAt;

		private float _winnerPendingReviveAt = -1f;

		private Vector3 _winnerDeathPos;

		private float _zeroPandoraSince = -1f;

		private readonly List<Character> _active = new List<Character>();

		private readonly List<Character> _pandoraAlive = new List<Character>();

		private readonly List<Character> _isolatedPandora = new List<Character>();

		private readonly HashSet<string> _activeIds = new HashSet<string>();

		private readonly HashSet<string> _currentIds = new HashSet<string>();

		private readonly HashSet<string> _appearanceHandled = new HashSet<string>();

		private readonly Dictionary<string, bool> _lastDead = new Dictionary<string, bool>();

		private readonly HashSet<string> _deathRecorded = new HashSet<string>();

		private readonly HashSet<string> _joinDead = new HashSet<string>();

		private readonly Dictionary<string, float> _authorizedReviveAt = new Dictionary<string, float>();

		private readonly Dictionary<string, float> _pandoraDeathTimes = new Dictionary<string, float>();

		private readonly Dictionary<string, Vector3> _pandoraDeathPositions = new Dictionary<string, Vector3>();

		private readonly Dictionary<string, int> _lastStatus = new Dictionary<string, int>();

		private float _nextAntiIsolationTeleport;

		private float _nextIsolatedScoutmaster;

		private readonly Dictionary<string, float> _antiIsolationTeleportAt = new Dictionary<string, float>();

		private readonly List<ScoutmasterLink> _scoutmasterLinks = new List<ScoutmasterLink>();

		private readonly Dictionary<PhotonView, FlagRecord> _flagsByView = new Dictionary<PhotonView, FlagRecord>();

		private readonly Dictionary<string, List<FlagRecord>> _flagsByPlayer = new Dictionary<string, List<FlagRecord>>();

		public static PandoraModeManager Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			_sawAirport = IsInAirportScene();
			PandoraModeBridge.NewLevelStarted += OnNewLevelStarted;
		}

		private void OnDestroy()
		{
			PandoraModeBridge.NewLevelStarted -= OnNewLevelStarted;
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}

		private void Update()
		{
			if ((Object)(object)Instance != (Object)(object)this)
			{
				return;
			}
			if (!PhotonNetwork.InRoom)
			{
				ResetRunState();
				PandoraModeBridge.Reset();
				PandoraModeBridge.SuppressAssignments = false;
				_sawAirport = IsInAirportScene();
			}
			else if (IsInAirportScene())
			{
				_sawAirport = true;
				if (_runLatched)
				{
					ResetRunState();
				}
				PandoraModeBridge.SuppressAssignments = PandoraModeConfig.Enabled.Value && ModConfig.General.Enabled.Value;
				PandoraModeBridge.Active = false;
				PandoraModeBridge.DisplayActive = false;
				PandoraModeBridge.OverridesActive = false;
				PandoraModeBridge.ReclassDisabled = false;
			}
			else
			{
				if (!PhotonNetwork.IsMasterClient || !GameHandler.IsInGameplayScene)
				{
					return;
				}
				if (!_runLatched)
				{
					if (!_sawAirport)
					{
						return;
					}
					_runLatched = true;
					_sawAirport = false;
					_runEnabled = PandoraModeConfig.Enabled.Value && ModConfig.General.Enabled.Value;
					if (!_runEnabled)
					{
						PandoraModeBridge.SuppressAssignments = false;
						return;
					}
					PandoraModeBridge.SuppressAssignments = true;
					ApplyModeRuntime(active: true);
				}
				if (_modeAborted)
				{
					return;
				}
				if (_modeEnded)
				{
					HostApi.FillActiveCharacters(_active);
					TickEndedState();
				}
				else if (_runEnabled && !ModConfig.General.Enabled.Value)
				{
					AbortMode("主模组总开关已关闭");
				}
				else
				{
					if (!_runEnabled)
					{
						return;
					}
					int num = (((Object)(object)HostClassManager.Instance != (Object)null) ? HostClassManager.Instance.LevelSerial : 0);
					if (num > 0 && num != _handledSerial)
					{
						HandleLevel(num);
					}
					if (_levelIndex > 0)
					{
						HostApi.FillActiveCharacters(_active);
						if (_active.Count != 0)
						{
							TickJoinsAndActiveSet();
							TickPrep();
							TickDeaths();
							TickStatusDisplay();
							TickScoutmasterLinks();
							TickAntiIsolationTeleport();
							TickIsolatedScoutmasters();
							TickVictory();
							TickWinner();
							TickOvertime();
							UpdateLiveOverrides();
						}
					}
				}
			}
		}

		private void ApplyModeRuntime(bool active)
		{
			PandoraModeBridge.Active = active;
			PandoraModeBridge.DisplayActive = active;
			PandoraModeBridge.OverridesActive = active;
			PandoraModeBridge.ReclassDisabled = active;
			if (active)
			{
				PandoraModeBridge.PandoraMaxPlayers = 99;
				PandoraModeBridge.PandoraBoxIntervalSeconds = 5f;
				PandoraModeBridge.PandoraBoxRadius = Mathf.Max(0f, PandoraModeConfig.PandoraEffectRadius.Value);
			}
		}

		private void UpdateLiveOverrides()
		{
			if (PandoraModeBridge.OverridesActive)
			{
				PandoraModeBridge.PandoraBoxRadius = Mathf.Max(0f, PandoraModeConfig.PandoraEffectRadius.Value);
			}
		}

		private void AbortMode(string reason)
		{
			if (!_modeAborted)
			{
				_modeAborted = true;
				_nextAntiIsolationTeleport = 0f;
				_nextIsolatedScoutmaster = 0f;
				_antiIsolationTeleportAt.Clear();
				EscapeAllScoutmasters();
				PandoraModeBridge.Active = false;
				PandoraModeBridge.DisplayActive = false;
				PandoraModeBridge.OverridesActive = false;
				PandoraModeBridge.ReclassDisabled = false;
				PandoraModeBridge.SuppressAssignments = false;
				PandoraModeBridge.RequestDisplaySync();
				Plugin.Log.LogWarning((object)("[RollOfTheScoutPandora] 模式已停止:" + reason + "。"));
			}
		}

		private void OnNewLevelStarted(int serial)
		{
			if (!((Object)(object)Instance != (Object)(object)this) && _runLatched && _runEnabled && !_modeAborted)
			{
				HandleLevel(serial);
			}
		}

		private void HandleLevel(int serial)
		{
			if (serial == _handledSerial)
			{
				return;
			}
			_handledSerial = serial;
			if (_modeEnded)
			{
				EnsureAllNoneEntries();
				PandoraModeBridge.RequestDisplaySync();
				return;
			}
			int levelIndex = GetLevelIndex(serial);
			if (levelIndex > 5)
			{
				EndModeAfterFifth("进入第 5 关之后的关卡");
			}
			else
			{
				StartLevel(serial, levelIndex);
			}
		}

		private int GetLevelIndex(int serial)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected I4, but got Unknown
			try
			{
				if (MapHandler.Exists)
				{
					int num = (int)MapHandler.CurrentSegmentNumber;
					if (num >= 0 && num <= 6)
					{
						return num + 1;
					}
				}
			}
			catch
			{
			}
			return serial;
		}

		private void StartLevel(int serial, int levelIndex)
		{
			_levelIndex = levelIndex;
			ApplyModeRuntime(active: true);
			PandoraModeBridge.SuppressAssignments = true;
			PandoraModeBridge.PandoraMaxPlayers = 99;
			PandoraModeBridge.PandoraBoxIntervalSeconds = 5f;
			PandoraModeBridge.PandoraBoxRadius = Mathf.Max(0f, PandoraModeConfig.PandoraEffectRadius.Value);
			PandoraModeBridge.ClearAllClasses();
			ResetLevelState();
			HostApi.FillActiveCharacters(_active);
			MarkCurrentAppearancesHandled();
			ForceSkeletonAllAlive();
			_prepActive = true;
			_prepStarted = Time.time;
			ApplyInvincibleToAllAlive("准备期");
			_nextInvincible = Time.time + 10f;
			PandoraModeBridge.RequestDisplaySync();
			Plugin.Log.LogInfo((object)($"[RollOfTheScoutPandora] 第 {levelIndex} 关开始:全员无职业 + 骷髅,准备期 " + $"{Mathf.Max(0f, PandoraModeConfig.PreparationSeconds.Value):0.#} 秒。"));
		}

		private void ResetLevelState()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			_prepActive = false;
			_winnerDetermined = false;
			_winnerLeft = false;
			_teleportPending = false;
			_rewardPending = false;
			_winnerReviveDone = false;
			_winnerId = null;
			_teleportScheduledAt = 0f;
			_winnerPendingReviveAt = -1f;
			_winnerDeathPos = Vector3.zero;
			_zeroPandoraSince = -1f;
			_nextAntiIsolationTeleport = 0f;
			_nextIsolatedScoutmaster = 0f;
			_antiIsolationTeleportAt.Clear();
			EscapeAllScoutmasters();
			_lastDead.Clear();
			_deathRecorded.Clear();
			_joinDead.Clear();
			_authorizedReviveAt.Clear();
			_pandoraDeathTimes.Clear();
			_pandoraDeathPositions.Clear();
			_lastStatus.Clear();
			_activeIds.Clear();
			_currentIds.Clear();
			_appearanceHandled.Clear();
			_flagsByView.Clear();
			_flagsByPlayer.Clear();
		}

		private void ResetRunState()
		{
			_runLatched = false;
			_runEnabled = false;
			_modeAborted = false;
			_modeEnded = false;
			_handledSerial = 0;
			_levelIndex = 0;
			ResetLevelState();
			PandoraModeBridge.Active = false;
			PandoraModeBridge.DisplayActive = false;
			PandoraModeBridge.OverridesActive = false;
			PandoraModeBridge.ReclassDisabled = false;
		}

		private void EndModeAfterFifth(string reason)
		{
			if (!_modeEnded)
			{
				_modeEnded = true;
				_prepActive = false;
				_teleportPending = false;
				_rewardPending = false;
				_zeroPandoraSince = -1f;
				_winnerPendingReviveAt = -1f;
				_pandoraDeathTimes.Clear();
				_pandoraDeathPositions.Clear();
				_nextAntiIsolationTeleport = 0f;
				_nextIsolatedScoutmaster = 0f;
				_antiIsolationTeleportAt.Clear();
				EscapeAllScoutmasters();
				PandoraModeBridge.Active = false;
				PandoraModeBridge.DisplayActive = false;
				PandoraModeBridge.OverridesActive = false;
				PandoraModeBridge.ReclassDisabled = false;
				PandoraModeBridge.SuppressAssignments = true;
				PandoraModeBridge.ClearAllClasses();
				EnsureAllNoneEntries();
				PandoraModeBridge.RequestDisplaySync();
				Plugin.Log.LogInfo((object)("[RollOfTheScoutPandora] 模式结束:" + reason + "。全员保持无职业,面板恢复为职业面板。"));
			}
		}

		private void TickEndedState()
		{
			PandoraModeBridge.SuppressAssignments = true;
			PandoraModeBridge.Active = false;
			PandoraModeBridge.DisplayActive = false;
			PandoraModeBridge.OverridesActive = false;
			PandoraModeBridge.ReclassDisabled = false;
			EnsureAllNoneEntries();
		}

		private void EnsureAllNoneEntries()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			HostApi.FillActiveCharacters(_active);
			foreach (Character item in _active)
			{
				if ((Object)(object)HostClassManager.Instance == (Object)null)
				{
					break;
				}
				if ((int)HostClassManager.Instance.GetClassOf(item) != 0 || !HostClassManager.Instance.ModeHasClassEntry(item))
				{
					PandoraModeBridge.ForceAssign(item, (ClassType)0);
				}
			}
		}

		private void TickPrep()
		{
			if (_prepActive)
			{
				if (Time.time >= _nextInvincible)
				{
					ApplyInvincibleToAllAlive("准备期");
					_nextInvincible = Time.time + 10f;
				}
				float num = Mathf.Max(0f, PandoraModeConfig.PreparationSeconds.Value);
				if (Time.time - _prepStarted >= num)
				{
					EndPrep();
				}
			}
		}

		private void EndPrep()
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Invalid comparison between Unknown and I4
			if (!_prepActive)
			{
				return;
			}
			_prepActive = false;
			HostApi.FillActiveCharacters(_active);
			int num = 0;
			foreach (Character item in _active)
			{
				if (IsAlive(item) && !((Object)(object)HostClassManager.Instance == (Object)null))
				{
					if ((int)HostClassManager.Instance.GetClassOf(item) != 6 && PandoraModeBridge.ForceAssign(item, (ClassType)6))
					{
						num++;
					}
					SetSkeleton(item, value: true);
				}
			}
			_nextAntiIsolationTeleport = Time.time + 10f;
			_nextIsolatedScoutmaster = Time.time + 15f;
			PandoraModeBridge.ResetPandoraTimers();
			PandoraModeBridge.RequestDisplaySync();
			Plugin.Log.LogInfo((object)$"[RollOfTheScoutPandora] 准备期结束:{num} 名存活玩家转为潘多拉之子,大逃杀开始。");
		}

		private void ApplyInvincibleToAllAlive(string reason)
		{
			foreach (Character item in _active)
			{
				if (IsAlive(item))
				{
					PandoraModeBridge.GrantInvincible(item, "潘多拉大乱斗·" + reason);
				}
			}
		}

		private void ForceSkeletonAllAlive()
		{
			foreach (Character item in _active)
			{
				if (!((Object)(object)item == (Object)null) && !((Object)(object)item.data == (Object)null) && !item.data.dead)
				{
					SetSkeleton(item, value: true);
				}
			}
		}

		private void MarkCurrentAppearancesHandled()
		{
			_activeIds.Clear();
			_appearanceHandled.Clear();
			foreach (Character item in _active)
			{
				string text = StableId(item);
				if (!string.IsNullOrEmpty(text))
				{
					_activeIds.Add(text);
					_appearanceHandled.Add(text);
					_lastDead[text] = IsTrueDead(item);
				}
			}
		}

		private void TickJoinsAndActiveSet()
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Invalid comparison between Unknown and I4
			HashSet<string> currentIds = _currentIds;
			currentIds.Clear();
			foreach (Character item in _active)
			{
				string text = StableId(item);
				if (!string.IsNullOrEmpty(text))
				{
					currentIds.Add(text);
					if (!_activeIds.Contains(text))
					{
						HandleAppearance(item, text);
						_appearanceHandled.Add(text);
						_lastDead[text] = IsTrueDead(item);
					}
					else if (!_appearanceHandled.Contains(text))
					{
						HandleAppearance(item, text);
						_appearanceHandled.Add(text);
					}
					if (!_modeEnded && !_winnerDetermined && (Object)(object)HostClassManager.Instance != (Object)null && (int)HostClassManager.Instance.GetClassOf(item) == 6 && !IsTrueDead(item))
					{
						SetSkeleton(item, value: true);
					}
				}
			}
			foreach (string activeId in _activeIds)
			{
				if (!currentIds.Contains(activeId))
				{
					_appearanceHandled.Remove(activeId);
					_lastDead.Remove(activeId);
					_deathRecorded.Remove(activeId);
					_joinDead.Remove(activeId);
					_authorizedReviveAt.Remove(activeId);
					_pandoraDeathTimes.Remove(activeId);
					_pandoraDeathPositions.Remove(activeId);
					_lastStatus.Remove(activeId);
				}
			}
			_activeIds.Clear();
			foreach (string item2 in currentIds)
			{
				_activeIds.Add(item2);
			}
		}

		private void HandleAppearance(Character character, string id)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Invalid comparison between Unknown and I4
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Invalid comparison between Unknown and I4
			bool flag = IsAlive(character);
			if (!flag)
			{
				_joinDead.Add(id);
			}
			else
			{
				_joinDead.Remove(id);
			}
			if (_modeEnded)
			{
				PandoraModeBridge.ForceAssign(character, (ClassType)0);
				return;
			}
			if (_winnerDetermined)
			{
				PandoraModeBridge.ForceAssign(character, (ClassType)0);
				return;
			}
			ClassType val = (ClassType)(((Object)(object)HostClassManager.Instance != (Object)null) ? ((int)HostClassManager.Instance.GetClassOf(character)) : 0);
			if (_prepActive)
			{
				if ((int)val != 6)
				{
					PandoraModeBridge.ForceAssign(character, (ClassType)0);
				}
				if (flag)
				{
					SetSkeleton(character, value: true);
					PandoraModeBridge.GrantInvincible(character, "潘多拉大乱斗·准备期加入");
				}
			}
			else if ((int)val == 6)
			{
				if (!IsTrueDead(character))
				{
					SetSkeleton(character, value: true);
				}
			}
			else if (flag)
			{
				PandoraModeBridge.ForceAssign(character, (ClassType)6);
				SetSkeleton(character, value: true);
			}
			else
			{
				PandoraModeBridge.ForceAssign(character, (ClassType)0);
			}
		}

		private void TickDeaths()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			foreach (Character item in _active)
			{
				string text = StableId(item);
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				bool flag = IsTrueDead(item);
				if (!_lastDead.TryGetValue(text, out var value))
				{
					_lastDead[text] = flag;
					continue;
				}
				if (!value && flag)
				{
					RecordDeath(item, item.Center, allowToast: true);
				}
				else if (value && !flag)
				{
					HandleRevival(item);
				}
				_lastDead[text] = flag;
			}
		}

		public void OnCharacterDied(Character character)
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			if (!PhotonNetwork.IsMasterClient || (Object)(object)character == (Object)null || !_runLatched || !_runEnabled || _modeAborted || _modeEnded)
			{
				return;
			}
			string text = StableId(character);
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			if (!_appearanceHandled.Contains(text))
			{
				_lastDead[text] = true;
				_deathRecorded.Add(text);
				return;
			}
			if (_winnerDetermined && text == _winnerId)
			{
				_winnerDeathPos = character.Center;
			}
			RecordDeath(character, character.Center, allowToast: true);
		}

		private void RecordDeath(Character character, Vector3 position, bool allowToast)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			string text = StableId(character);
			if (!string.IsNullOrEmpty(text) && _deathRecorded.Add(text))
			{
				_lastDead[text] = true;
				if ((((Object)(object)HostClassManager.Instance != (Object)null) ? ((int)HostClassManager.Instance.GetClassOf(character)) : 0) == 6)
				{
					_pandoraDeathTimes[text] = Time.time;
					_pandoraDeathPositions[text] = position;
				}
				bool flag = _appearanceHandled.Contains(text) && !_joinDead.Contains(text);
				if (allowToast && flag && !_modeEnded && (PandoraModeBridge.DisplayActive || _winnerDetermined))
				{
					ShowDeathToast(character);
				}
				PandoraModeBridge.RequestDisplaySync();
			}
		}

		private void HandleRevival(Character character)
		{
			string text = StableId(character);
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			_deathRecorded.Remove(text);
			_joinDead.Remove(text);
			_lastDead[text] = false;
			_pandoraDeathTimes.Remove(text);
			_pandoraDeathPositions.Remove(text);
			if (_authorizedReviveAt.TryGetValue(text, out var value) && Time.time - value <= 2f)
			{
				return;
			}
			if (_modeEnded)
			{
				PandoraModeBridge.ForceAssign(character, (ClassType)0);
				PandoraModeBridge.RequestDisplaySync();
			}
			else if (_winnerDetermined)
			{
				if (text == _winnerId)
				{
					ProtectWinnerAfterRevive(character);
				}
				else
				{
					PandoraModeBridge.ForceAssign(character, (ClassType)0);
					SetSkeleton(character, value: false);
				}
				PandoraModeBridge.RequestDisplaySync();
			}
			else if (_prepActive)
			{
				PandoraModeBridge.ForceAssign(character, (ClassType)0);
				SetSkeleton(character, value: true);
				PandoraModeBridge.RequestDisplaySync();
			}
			else
			{
				PandoraModeBridge.ForceAssign(character, (ClassType)0);
				SetSkeleton(character, value: false);
				PandoraModeBridge.RequestDisplaySync();
				Plugin.Log.LogInfo((object)("[RollOfTheScoutPandora] 违规复活:" + Nickname(character) + " 已恢复为人类无职业,不参与赢家判定。"));
			}
		}

		public void OnCheckpointRegain(Character character)
		{
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Invalid comparison between Unknown and I4
			if (!PhotonNetwork.IsMasterClient || (Object)(object)character == (Object)null || !_runLatched || !_runEnabled || _modeAborted)
			{
				return;
			}
			string text = StableId(character);
			if (string.IsNullOrEmpty(text))
			{
				return;
			}
			_authorizedReviveAt[text] = Time.time;
			_deathRecorded.Remove(text);
			_joinDead.Remove(text);
			_lastDead[text] = false;
			_pandoraDeathTimes.Remove(text);
			_pandoraDeathPositions.Remove(text);
			if (_modeEnded)
			{
				PandoraModeBridge.ForceAssign(character, (ClassType)0);
				PandoraModeBridge.RequestDisplaySync();
				return;
			}
			if (_winnerDetermined)
			{
				if (text == _winnerId)
				{
					TakeLastFlag(text);
					ProtectWinnerAfterRevive(character);
				}
				else
				{
					TakeLastFlag(text);
					PandoraModeBridge.ForceAssign(character, (ClassType)0);
				}
				PandoraModeBridge.RequestDisplaySync();
				return;
			}
			FlagRecord flagRecord = TakeLastFlag(text);
			if (flagRecord == null)
			{
				Plugin.Log.LogWarning((object)("[RollOfTheScoutPandora] 检查点复活缺少插旗记录:" + Nickname(character) + ",按违规复活处理。"));
				PandoraModeBridge.ForceAssign(character, (ClassType)0);
				SetSkeleton(character, value: false);
			}
			else if ((int)flagRecord.ClassAtPlant == 6)
			{
				PandoraModeBridge.ForceAssign(character, (ClassType)6);
				SetSkeleton(character, value: true);
				Plugin.Log.LogInfo((object)("[RollOfTheScoutPandora] 检查点复活:" + Nickname(character) + " 恢复为潘多拉之子(插旗时为潘多拉)。"));
			}
			else
			{
				PandoraModeBridge.ForceAssign(character, (ClassType)0);
				SetSkeleton(character, flagRecord.SkeletonAtPlant);
				Plugin.Log.LogInfo((object)("[RollOfTheScoutPandora] 检查点复活:" + Nickname(character) + " 恢复为插旗时的无职业状态,不参与赢家判定。"));
			}
			PandoraModeBridge.RequestDisplaySync();
		}

		private void ProtectWinnerAfterRevive(Character winner)
		{
			if (!_modeEnded && !((Object)(object)winner == (Object)null))
			{
				HostApi.ClearAllNegativeStatuses(winner);
				PandoraModeBridge.GrantInvincible(winner, "潘多拉大乱斗·赢家保护");
				SetSkeleton(winner, value: true);
				_teleportPending = true;
				_teleportScheduledAt = Time.time;
				_winnerPendingReviveAt = -1f;
				PandoraModeBridge.RequestDisplaySync();
				Plugin.Log.LogInfo((object)("[RollOfTheScoutPandora] 赢家保护:" + Nickname(winner) + " 已复活,3 秒后重新传送。"));
			}
		}

		private void TickVictory()
		{
			if (_modeEnded || _prepActive || _winnerDetermined)
			{
				return;
			}
			FillAlivePandora();
			if (_pandoraAlive.Count == 1)
			{
				_zeroPandoraSince = -1f;
				DetermineWinner(_pandoraAlive[0]);
			}
			else if (_pandoraAlive.Count == 0)
			{
				if (_zeroPandoraSince < 0f)
				{
					_zeroPandoraSince = Time.time;
				}
			}
			else
			{
				_zeroPandoraSince = -1f;
			}
		}

		private void FillAlivePandora()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Invalid comparison between Unknown and I4
			_pandoraAlive.Clear();
			if ((Object)(object)HostClassManager.Instance == (Object)null)
			{
				return;
			}
			foreach (Character item in _active)
			{
				if ((int)HostClassManager.Instance.GetClassOf(item) == 6 && IsAlive(item))
				{
					_pandoraAlive.Add(item);
				}
			}
		}

		private void DetermineWinner(Character winner)
		{
			if (!((Object)(object)winner == (Object)null) && !_winnerDetermined)
			{
				_winnerId = StableId(winner);
				_winnerDetermined = true;
				_zeroPandoraSince = -1f;
				_winnerLeft = false;
				_winnerPendingReviveAt = -1f;
				PandoraModeBridge.ClearAllClasses();
				HostApi.ClearAllNegativeStatuses(winner);
				PandoraModeBridge.GrantInvincible(winner, "潘多拉大乱斗·赢家");
				SetSkeleton(winner, value: true);
				_teleportPending = true;
				_teleportScheduledAt = Time.time;
				_rewardPending = true;
				_pandoraDeathTimes.Clear();
				_pandoraDeathPositions.Clear();
				_nextAntiIsolationTeleport = 0f;
				_nextIsolatedScoutmaster = 0f;
				_antiIsolationTeleportAt.Clear();
				EscapeAllScoutmasters();
				ShowWinnerToast(winner);
				PandoraModeBridge.RequestDisplaySync();
				Plugin.Log.LogInfo((object)("[RollOfTheScoutPandora] 本轮最终获胜玩家:" + Nickname(winner) + "。"));
			}
		}

		private void TickWinner()
		{
			if (_modeEnded || !_winnerDetermined || _winnerLeft)
			{
				return;
			}
			Character val = FindCharacter(_winnerId);
			if ((Object)(object)val == (Object)null)
			{
				_winnerLeft = true;
				_teleportPending = false;
				_rewardPending = false;
				PandoraModeBridge.RequestDisplaySync();
				Plugin.Log.LogInfo((object)"[RollOfTheScoutPandora] 赢家已离开,模式不再触发加时/保护,等待原版结束或其它玩家开启古老雕像。");
			}
			else if (IsTrueDead(val))
			{
				if (_winnerPendingReviveAt < 0f)
				{
					_winnerPendingReviveAt = Time.time + 0.35f;
				}
				else if (Time.time >= _winnerPendingReviveAt)
				{
					ReviveWinnerAtDeath(val);
				}
			}
			else
			{
				_winnerPendingReviveAt = -1f;
				if (_teleportPending && TeleportDue())
				{
					TeleportWinner(val);
				}
			}
		}

		private bool TeleportDue()
		{
			float num = Mathf.Max(0f, PandoraModeConfig.TeleportDelaySeconds.Value);
			return Time.time >= _teleportScheduledAt + num;
		}

		private void ReviveWinnerAtDeath(Character winner)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			_winnerPendingReviveAt = -1f;
			Vector3 val = ((_winnerDeathPos != Vector3.zero) ? _winnerDeathPos : winner.Center);
			((MonoBehaviourPun)winner).photonView.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { val, false, -1 });
			HostApi.ClearAllNegativeStatuses(winner);
			PandoraModeBridge.GrantInvincible(winner, "潘多拉大乱斗·赢家保护");
			SetSkeleton(winner, value: true);
			_teleportPending = true;
			_teleportScheduledAt = Time.time;
			PandoraModeBridge.RequestDisplaySync();
			Plugin.Log.LogInfo((object)("[RollOfTheScoutPandora] 赢家死亡保护:" + Nickname(winner) + " 已在死亡位置复活,3 秒后重新传送。"));
		}

		private void TeleportWinner(Character winner)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)winner == (Object)null) && !_winnerLeft)
			{
				Vector3 teleportTarget = GetTeleportTarget(winner);
				((MonoBehaviourPun)winner).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { teleportTarget, true });
				_teleportPending = false;
				if (_rewardPending)
				{
					GrantWinnerReward(winner, teleportTarget);
					_rewardPending = false;
				}
				if (!_winnerReviveDone)
				{
					_winnerReviveDone = true;
					ReviveAllAtWinner(winner, teleportTarget);
				}
				if (_levelIndex >= 5)
				{
					EndModeAfterFifth("第五关赢家流程完成");
				}
				PandoraModeBridge.RequestDisplaySync();
				Plugin.Log.LogInfo((object)$"[RollOfTheScoutPandora] 赢家已传送:{Nickname(winner)} → {teleportTarget}。");
			}
		}

		private Vector3 GetTeleportTarget(Character winner)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if (_levelIndex >= 5)
			{
				Vector3 peakSummitTarget = GetPeakSummitTarget();
				if (peakSummitTarget != Vector3.zero)
				{
					return peakSummitTarget;
				}
			}
			try
			{
				Campfire currentCampfire = MapHandler.CurrentCampfire;
				if ((Object)(object)currentCampfire != (Object)null)
				{
					return ((Component)currentCampfire).transform.position + CharacterSpawner.RandomBaseCampOffset;
				}
				RespawnChest currentScoutStatue = MapHandler.CurrentScoutStatue;
				if ((Object)(object)currentScoutStatue != (Object)null)
				{
					return ((Component)currentScoutStatue).transform.position + CharacterSpawner.RandomBaseCampOffset;
				}
				Transform currentBaseCampSpawnPoint = MapHandler.CurrentBaseCampSpawnPoint;
				if ((Object)(object)currentBaseCampSpawnPoint != (Object)null)
				{
					return currentBaseCampSpawnPoint.position + CharacterSpawner.RandomBaseCampOffset;
				}
			}
			catch
			{
			}
			if (!((Object)(object)winner != (Object)null))
			{
				return Vector3.up * 1.5f;
			}
			return winner.Center + Vector3.up * 1.5f;
		}

		private static Vector3 GetPeakSummitTarget()
		{
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				MapHandler instance = Singleton<MapHandler>.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.ForceEnablePeak();
				}
			}
			catch
			{
			}
			try
			{
				PeakHandler instance2 = Singleton<PeakHandler>.Instance;
				if ((Object)(object)instance2 != (Object)null && (Object)(object)instance2.flareBox != (Object)null)
				{
					return instance2.flareBox.transform.position + Vector3.up * 1.5f;
				}
			}
			catch
			{
			}
			try
			{
				MountainProgressHandler instance3 = Singleton<MountainProgressHandler>.Instance;
				if ((Object)(object)instance3 != (Object)null && instance3.progressPoints != null && instance3.progressPoints.Length != 0)
				{
					ProgressPoint val = instance3.progressPoints[instance3.progressPoints.Length - 1];
					if (val != null && (Object)(object)val.transform != (Object)null)
					{
						return val.transform.position + Vector3.up * 1.5f;
					}
				}
			}
			catch
			{
			}
			try
			{
				PeakHandler instance4 = Singleton<PeakHandler>.Instance;
				if ((Object)(object)instance4 != (Object)null)
				{
					MonoBehaviour[] componentsInChildren = ((Component)instance4).gameObject.GetComponentsInChildren<MonoBehaviour>(true);
					foreach (MonoBehaviour val2 in componentsInChildren)
					{
						if (!((Object)(object)val2 == (Object)null) && !(((object)val2).GetType().Name != "ScoutStatue"))
						{
							FieldInfo field = ((object)val2).GetType().GetField("gemSpot", BindingFlags.Instance | BindingFlags.Public);
							Transform val3 = (Transform)((field != null) ? /*isinst with value type is only supported in some contexts*/: null);
							if ((Object)(object)val3 != (Object)null)
							{
								return val3.position + Vector3.up * 1.5f;
							}
						}
					}
				}
			}
			catch
			{
			}
			return Vector3.zero;
		}

		private void GrantWinnerReward(Character winner, Vector3 teleportTarget)
		{
			//IL_008e: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			string text = PandoraModeConfig.WinnerRewardItem.Value;
			if (string.IsNullOrEmpty(text))
			{
				text = "Flag_Plantable_Checkpoint";
			}
			int num = Mathf.Max(0, PandoraModeConfig.WinnerRewardCount.Value);
			if (num == 0)
			{
				return;
			}
			int num2 = 0;
			ItemSlot val = default(ItemSlot);
			for (int i = 0; i < num; i++)
			{
				if (HostApi.GiveItemToInventorySlots(winner, text, ref val))
				{
					num2++;
				}
				else if (HostApi.GiveItemForceHold(winner, text, ref val))
				{
					num2++;
				}
				else if (_levelIndex >= 5)
				{
					if ((Object)(object)HostApi.SpawnWorldItem(text, teleportTarget + Vector3.up * 0.5f, Quaternion.identity) != (Object)null)
					{
						num2++;
					}
				}
				else if ((Object)(object)HostApi.SpawnItemFixedNearCampfire(text, teleportTarget) != (Object)null)
				{
					num2++;
				}
			}
			if (num2 > 0)
			{
				Plugin.Log.LogInfo((object)$"[RollOfTheScoutPandora] 赢家奖励:{Nickname(winner)} 获得 {num2}/{num} 个 {text}。");
			}
			else
			{
				Plugin.Log.LogWarning((object)("[RollOfTheScoutPandora] 赢家奖励发放失败:物品 " + text + " 无效或无法生成。"));
			}
		}

		private void ReviveAllAtWinner(Character winner, Vector3 center)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)winner == (Object)null)
			{
				return;
			}
			int num = 0;
			foreach (Character item in _active)
			{
				if (!((Object)(object)item == (Object)null) && !((Object)(object)item == (Object)(object)winner) && !((Object)(object)item.data == (Object)null) && (item.data.dead || item.data.fullyPassedOut))
				{
					Vector3 val = center + new Vector3(Random.Range(-1.5f, 1.5f), 1.2f, Random.Range(-1.5f, 1.5f));
					((MonoBehaviourPun)item).photonView.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { val, false, -1 });
					_authorizedReviveAt[StableId(item)] = Time.time;
					PandoraModeBridge.ForceAssign(item, (ClassType)0);
					num++;
				}
			}
			Plugin.Log.LogInfo((object)$"[RollOfTheScoutPandora] 赢家流程:已在赢家周围复活 {num} 名玩家。");
		}

		private void TickOvertime()
		{
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			if (_modeEnded || _prepActive || _winnerDetermined || _zeroPandoraSince < 0f || Time.time - _zeroPandoraSince < 1f)
			{
				return;
			}
			float num = float.MinValue;
			foreach (float value2 in _pandoraDeathTimes.Values)
			{
				if (value2 > num)
				{
					num = value2;
				}
			}
			if (num == float.MinValue)
			{
				_zeroPandoraSince = Time.time;
				return;
			}
			int num2 = 0;
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, float> pandoraDeathTime in _pandoraDeathTimes)
			{
				if (pandoraDeathTime.Value >= num - 1f)
				{
					list.Add(pandoraDeathTime.Key);
				}
			}
			foreach (string item in list)
			{
				Character val = FindCharacter(item);
				if (!((Object)(object)val == (Object)null) && IsTrueDead(val))
				{
					Vector3 value;
					Vector3 val2 = ((_pandoraDeathPositions.TryGetValue(item, out value) && value != Vector3.zero) ? value : val.Center);
					((MonoBehaviourPun)val).photonView.RPC("RPCA_ReviveAtPosition", (RpcTarget)0, new object[3] { val2, false, -1 });
					_authorizedReviveAt[item] = Time.time;
					PandoraModeBridge.ForceAssign(val, (ClassType)6);
					SetSkeleton(val, value: true);
					_deathRecorded.Remove(item);
					_lastDead[item] = false;
					_pandoraDeathTimes.Remove(item);
					_pandoraDeathPositions.Remove(item);
					num2++;
				}
			}
			_zeroPandoraSince = -1f;
			PandoraModeBridge.RequestDisplaySync();
			Plugin.Log.LogInfo((object)$"[RollOfTheScoutPandora] 加时重赛:复活最近死亡批次的 {num2} 名潘多拉之子。");
		}

		private void TickAntiIsolationTeleport()
		{
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < _nextAntiIsolationTeleport)
			{
				return;
			}
			_nextAntiIsolationTeleport = Time.time + 10f;
			if (!PandoraModeConfig.AntiIsolationTeleportEnabled.Value || _prepActive || _winnerDetermined || _modeEnded)
			{
				return;
			}
			FillAlivePandora();
			if (_pandoraAlive.Count <= 1)
			{
				return;
			}
			FillIsolatedPandora(Mathf.Max(1f, PandoraModeConfig.AntiIsolationTeleportRadius.Value));
			if (_isolatedPandora.Count == 0)
			{
				return;
			}
			Character val = _isolatedPandora[Random.Range(0, _isolatedPandora.Count)];
			if ((Object)(object)val == (Object)null || (Object)(object)((MonoBehaviourPun)val).photonView == (Object)null)
			{
				return;
			}
			Character val2 = null;
			int num = Random.Range(0, _pandoraAlive.Count - 1);
			foreach (Character item in _pandoraAlive)
			{
				if (!((Object)(object)item == (Object)(object)val) && num-- == 0)
				{
					val2 = item;
					break;
				}
			}
			if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((MonoBehaviourPun)val2).photonView == (Object)null))
			{
				Vector2 val3 = Random.insideUnitCircle * 1f;
				Vector3 val4 = val2.Center + new Vector3(val3.x, 0.5f, val3.y);
				((MonoBehaviourPun)val).photonView.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2] { val4, true });
				string text = StableId(val);
				if (!string.IsNullOrEmpty(text))
				{
					_antiIsolationTeleportAt[text] = Time.time;
				}
				Plugin.Log.LogInfo((object)("[RollOfTheScoutPandora] 防孤立传送:" + Nickname(val) + " 半径内无其他潘多拉,已传送到 " + Nickname(val2) + " 处。"));
			}
		}

		private void TickIsolatedScoutmasters()
		{
			if (Time.time < _nextIsolatedScoutmaster)
			{
				return;
			}
			_nextIsolatedScoutmaster = Time.time + 15f;
			if (!PandoraModeConfig.IsolatedScoutmasterEnabled.Value || _prepActive || _winnerDetermined || _modeEnded)
			{
				return;
			}
			FillAlivePandora();
			if (_pandoraAlive.Count <= 1)
			{
				return;
			}
			FillIsolatedPandora(Mathf.Max(1f, PandoraModeConfig.IsolatedScoutmasterRadius.Value));
			foreach (Character item in _isolatedPandora)
			{
				string text = StableId(item);
				if (!string.IsNullOrEmpty(text) && CountActiveLinksForTarget(text) < 2)
				{
					PhotonView val = PandoraModeBridge.SpawnScoutmaster(item, 10f, 30f);
					if (!((Object)(object)val == (Object)null))
					{
						_scoutmasterLinks.Add(new ScoutmasterLink
						{
							View = val,
							TargetId = text,
							SpawnedAt = Time.time,
							ExpireAt = Time.time + 30f
						});
						Plugin.Log.LogInfo((object)$"[RollOfTheScoutPandora] 孤立童军领队:已在 {Nickname(item)} 半径 {10f:0.#} 米外生成,追击 {30f:0.#} 秒。");
					}
				}
			}
		}

		private void TickScoutmasterLinks()
		{
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Invalid comparison between Unknown and I4
			if (_scoutmasterLinks.Count == 0)
			{
				return;
			}
			if (!PandoraModeConfig.IsolatedScoutmasterEnabled.Value)
			{
				EscapeAllScoutmasters();
				return;
			}
			for (int num = _scoutmasterLinks.Count - 1; num >= 0; num--)
			{
				ScoutmasterLink scoutmasterLink = _scoutmasterLinks[num];
				if (scoutmasterLink == null || (Object)(object)scoutmasterLink.View == (Object)null)
				{
					_scoutmasterLinks.RemoveAt(num);
				}
				else
				{
					Character val = FindCharacter(scoutmasterLink.TargetId);
					bool flag = (Object)(object)val == (Object)null || (Object)(object)val.data == (Object)null || IsTrueDead(val) || val.data.fullyPassedOut || ((Object)(object)HostClassManager.Instance != (Object)null && (int)HostClassManager.Instance.GetClassOf(val) != 6);
					if (!flag && _antiIsolationTeleportAt.TryGetValue(scoutmasterLink.TargetId, out var value))
					{
						flag = Time.time - value <= 2f;
					}
					if (flag || Time.time >= scoutmasterLink.ExpireAt)
					{
						EscapeScoutmaster(scoutmasterLink);
						_scoutmasterLinks.RemoveAt(num);
					}
				}
			}
		}

		private int CountActiveLinksForTarget(string targetId)
		{
			int num = 0;
			foreach (ScoutmasterLink scoutmasterLink in _scoutmasterLinks)
			{
				if (scoutmasterLink != null && !scoutmasterLink.Escaped && (Object)(object)scoutmasterLink.View != (Object)null && scoutmasterLink.TargetId == targetId)
				{
					num++;
				}
			}
			return num;
		}

		private void EscapeScoutmaster(ScoutmasterLink link)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if (link != null && !link.Escaped)
			{
				link.Escaped = true;
				PhotonView view = link.View;
				if (!((Object)(object)view == (Object)null))
				{
					view.RPC("RPCA_SetCurrentTarget", (RpcTarget)0, new object[2] { -1, 0f });
					view.RPC("WarpPlayerRPC", (RpcTarget)0, new object[2]
					{
						Character.ScoutmasterHideySpot,
						false
					});
					view.RPC("StopClimbingRpc", (RpcTarget)0, new object[1] { 0f });
				}
			}
		}

		private void EscapeAllScoutmasters()
		{
			if (_scoutmasterLinks.Count == 0)
			{
				return;
			}
			foreach (ScoutmasterLink scoutmasterLink in _scoutmasterLinks)
			{
				EscapeScoutmaster(scoutmasterLink);
			}
			_scoutmasterLinks.Clear();
		}

		private void FillIsolatedPandora(float radius)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			_isolatedPandora.Clear();
			if (_pandoraAlive.Count <= 1)
			{
				return;
			}
			float num = Mathf.Max(1f, radius);
			float num2 = num * num;
			foreach (Character item in _pandoraAlive)
			{
				if ((Object)(object)item == (Object)null || (Object)(object)item.data == (Object)null)
				{
					continue;
				}
				bool flag = true;
				foreach (Character item2 in _pandoraAlive)
				{
					if (!((Object)(object)item2 == (Object)(object)item) && !((Object)(object)item2 == (Object)null) && !((Object)(object)item2.data == (Object)null))
					{
						Vector3 val = item2.Center - item.Center;
						if (((Vector3)(ref val)).sqrMagnitude <= num2)
						{
							flag = false;
							break;
						}
					}
				}
				if (flag)
				{
					_isolatedPandora.Add(item);
				}
			}
		}

		public bool ShouldSuppressRespawnChestItems()
		{
			if (!_runLatched || !_runEnabled || _modeAborted || _modeEnded)
			{
				return false;
			}
			if (_levelIndex < 1 || _levelIndex > 4)
			{
				return false;
			}
			if (!Character.PlayerIsDeadOrDown())
			{
				return true;
			}
			return !Ascents.canReviveDead;
		}

		public void OnCheckpointFlagPlanted(CheckpointFlag flag)
		{
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			if (!PhotonNetwork.IsMasterClient || (Object)(object)flag == (Object)null || !_runLatched || !_runEnabled || _modeAborted || _modeEnded || _levelIndex < 1 || _levelIndex > 5 || (!PandoraModeBridge.Active && !_winnerDetermined))
			{
				return;
			}
			PhotonView component = ((Component)flag).GetComponent<PhotonView>();
			if ((Object)(object)component == (Object)null || component.Owner == null || _flagsByView.ContainsKey(component))
			{
				return;
			}
			Character val = (((Object)(object)HostClassManager.Instance != (Object)null) ? HostClassManager.Instance.FindCharacterOfPlayer(component.Owner) : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			string text = StableId(val);
			if (!string.IsNullOrEmpty(text))
			{
				FlagRecord flagRecord = new FlagRecord
				{
					View = component,
					PlayerId = text,
					ClassAtPlant = HostClassManager.Instance.GetClassOf(val),
					SkeletonAtPlant = ((Object)(object)val.data != (Object)null && val.data.isSkeleton)
				};
				_flagsByView[component] = flagRecord;
				if (!_flagsByPlayer.TryGetValue(text, out var value))
				{
					value = new List<FlagRecord>();
					_flagsByPlayer[text] = value;
				}
				value.Add(flagRecord);
			}
		}

		public void OnCheckpointFlagRemoved(CheckpointFlag flag)
		{
			if (!((Object)(object)flag == (Object)null))
			{
				PhotonView component = ((Component)flag).GetComponent<PhotonView>();
				if (!((Object)(object)component == (Object)null))
				{
					RemoveFlag(component);
				}
			}
		}

		private FlagRecord TakeLastFlag(string playerId)
		{
			if (!_flagsByPlayer.TryGetValue(playerId, out var value) || value.Count == 0)
			{
				return null;
			}
			int index = value.Count - 1;
			FlagRecord flagRecord = value[index];
			value.RemoveAt(index);
			if (flagRecord != null && (Object)(object)flagRecord.View != (Object)null)
			{
				_flagsByView.Remove(flagRecord.View);
			}
			return flagRecord;
		}

		private void RemoveFlag(PhotonView view)
		{
			if (!_flagsByView.TryGetValue(view, out var value))
			{
				return;
			}
			_flagsByView.Remove(view);
			if (value != null && _flagsByPlayer.TryGetValue(value.PlayerId, out var value2))
			{
				value2.Remove(value);
				if (value2.Count == 0)
				{
					_flagsByPlayer.Remove(value.PlayerId);
				}
			}
		}

		private void RemoveFlagsOfPlayer(string playerId)
		{
			if (!_flagsByPlayer.TryGetValue(playerId, out var value))
			{
				return;
			}
			foreach (FlagRecord item in value)
			{
				if (item != null && (Object)(object)item.View != (Object)null)
				{
					_flagsByView.Remove(item.View);
				}
			}
			_flagsByPlayer.Remove(playerId);
		}

		private void TickStatusDisplay()
		{
			if (!PandoraModeBridge.DisplayActive || _modeEnded)
			{
				return;
			}
			bool flag = false;
			foreach (Character item in _active)
			{
				string text = StableId(item);
				if (string.IsNullOrEmpty(text))
				{
					continue;
				}
				int num = PandoraModeBridge.StatusOf(item);
				if (_lastStatus.TryGetValue(text, out var value))
				{
					if (value != num)
					{
						flag = true;
					}
				}
				else
				{
					flag = true;
				}
				_lastStatus[text] = num;
			}
			if (flag)
			{
				PandoraModeBridge.RequestDisplaySync();
			}
		}

		private void ShowDeathToast(Character character)
		{
			string text = Nickname(character);
			PandoraModeBridge.ShowToast("【" + text + "】died");
			PandoraModeBridge.ShowToast("【" + text + "】死亡");
		}

		private void ShowWinnerToast(Character winner)
		{
			string text = Nickname(winner);
			PandoraModeBridge.ShowToast("Round winner: 【" + text + "】");
			PandoraModeBridge.ShowToast("本轮最终获胜玩家:【" + text + "】");
		}

		private static bool IsInAirportScene()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			if (((Scene)(ref activeScene)).IsValid())
			{
				return ((Scene)(ref activeScene)).name.Contains("Airport");
			}
			return false;
		}

		private static bool IsAlive(Character character)
		{
			if ((Object)(object)character == (Object)null || (Object)(object)character.data == (Object)null)
			{
				return false;
			}
			if (!character.data.dead && !character.data.passedOut)
			{
				return !character.data.fullyPassedOut;
			}
			return false;
		}

		private static bool IsTrueDead(Character character)
		{
			if ((Object)(object)character != (Object)null && (Object)(object)character.data != (Object)null)
			{
				return character.data.dead;
			}
			return false;
		}

		private static string StableId(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return null;
			}
			string text = PandoraModeBridge.StableIdOf(character);
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			PhotonView photonView = ((MonoBehaviourPun)character).photonView;
			if (!((Object)(object)photonView != (Object)null))
			{
				return null;
			}
			return "v:" + photonView.ViewID;
		}

		private Character FindCharacter(string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				return null;
			}
			foreach (Character item in _active)
			{
				if (StableId(item) == id)
				{
					return item;
				}
			}
			return null;
		}

		private static string Nickname(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return "?";
			}
			if (!string.IsNullOrEmpty(character.characterName))
			{
				return character.characterName;
			}
			Player val = (((Object)(object)((MonoBehaviourPun)character).photonView != (Object)null) ? ((MonoBehaviourPun)character).photonView.Owner : null);
			if (val == null || string.IsNullOrEmpty(val.NickName))
			{
				return "?";
			}
			return val.NickName;
		}

		private static void SetSkeleton(Character character, bool value)
		{
			if (!((Object)(object)character == (Object)null) && !((Object)(object)character.data == (Object)null) && character.data.isSkeleton != value)
			{
				character.data.SetSkeleton(value);
			}
		}
	}
	[BepInPlugin("com.peakmodding.RollOfTheScoutPandora", "RollOfTheScoutPandora", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.peakmodding.RollOfTheScoutPandora";

		internal static ManualLogSource Log;

		private const string ConfigRevision = "2026-11-04-pandora-2";

		private Harmony _harmony;

		internal static Harmony HarmonyInstance { get; private set; }

		private void Awake()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ResetOutdatedConfig(((BaseUnityPlugin)this).Config);
			PandoraModeConfig.Initialize(((BaseUnityPlugin)this).Config);
			((BaseUnityPlugin)this).Config.Save();
			((Component)this).gameObject.AddComponent<PandoraModeManager>();
			_harmony = new Harmony("com.peakmodding.RollOfTheScoutPandora");
			HarmonyInstance = _harmony;
			TryPatch("CheckpointFlag.SetColor", ResolveMethod(typeof(CheckpointFlag), "SetColor"), null, AccessTools.Method(typeof(CheckpointPatches), "SetColorPostfix", (Type[])null, (Type[])null));
			TryPatch("CheckpointFlag.OnDisable", ResolveMethod(typeof(CheckpointFlag), "OnDisable"), null, AccessTools.Method(typeof(CheckpointPatches), "OnDisablePostfix", (Type[])null, (Type[])null));
			TryPatch("CharacterData.RegainItems", ResolveMethod(typeof(CharacterData), "RegainItems"), null, AccessTools.Method(typeof(CheckpointPatches), "RegainItemsPostfix", (Type[])null, (Type[])null));
			TryPatch("CharacterData.RPCA_Die", ResolveMethod(typeof(CharacterData), "RPCA_Die"), null, AccessTools.Method(typeof(CheckpointPatches), "DiePostfix", (Type[])null, (Type[])null));
			TryPatch("RespawnChest.SpawnItems", ResolveMethod(typeof(RespawnChest), "SpawnItems"), AccessTools.Method(typeof(RespawnChestPatches), "SpawnItemsPrefix", (Type[])null, (Type[])null), null);
			Log.LogInfo((object)"[RollOfTheScoutPandora] 已加载。仅主机需要安装;需同时安装主模组 1.1.2。");
		}

		private void TryPatch(string label, MethodInfo target, MethodInfo prefix, MethodInfo postfix)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (target == null)
			{
				Log.LogWarning((object)("[RollOfTheScoutPandora] 未找到目标方法,跳过补丁:" + label));
				return;
			}
			try
			{
				_harmony.Patch((MethodBase)target, (!(prefix != null)) ? ((HarmonyMethod)null) : new HarmonyMethod(prefix), (!(postfix != null)) ? ((HarmonyMethod)null) : new HarmonyMethod(postfix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Log.LogInfo((object)("[RollOfTheScoutPandora] 补丁成功:" + label));
			}
			catch (Exception ex)
			{
				Log.LogError((object)("[RollOfTheScoutPandora] 补丁失败:" + label + " → " + ex.Message));
			}
		}

		private static MethodInfo ResolveMethod(Type type, string name)
		{
			MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name == name)
				{
					return methodInfo;
				}
			}
			return null;
		}

		private static void ResetOutdatedConfig(ConfigFile config)
		{
			try
			{
				string text = ((config != null) ? config.ConfigFilePath : null);
				if (!string.IsNullOrEmpty(text))
				{
					string path = text + ".rev";
					string a = (File.Exists(path) ? File.ReadAllText(path).Trim() : null);
					if (!File.Exists(text))
					{
						File.WriteAllText(path, "2026-11-04-pandora-2");
					}
					else if (!string.Equals(a, "2026-11-04-pandora-2", StringComparison.Ordinal))
					{
						string text2 = text + ".old-" + DateTime.Now.ToString("yyyyMMdd-HHmmss");
						File.Move(text, text2);
						File.WriteAllText(path, "2026-11-04-pandora-2");
						Log.LogWarning((object)("[RollOfTheScoutPandora] 配置文件结构已更新,旧配置已备份为 " + Path.GetFileName(text2) + ",并将重新生成默认配置。"));
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("[RollOfTheScoutPandora] 检查旧配置文件失败(已忽略):" + ex.Message));
			}
		}
	}
	public static class RespawnChestPatches
	{
		public static bool SpawnItemsPrefix(RespawnChest __instance, ref List<PhotonView> __result)
		{
			PandoraModeManager instance = PandoraModeManager.Instance;
			if ((Object)(object)instance == (Object)null || !instance.ShouldSuppressRespawnChestItems())
			{
				return true;
			}
			__result = new List<PhotonView>();
			return false;
		}
	}
}