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;
}
}
}