Decompiled source of DeathRoulette v1.2.0

DeathRoulette.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
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 UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("DeathRoulette")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.2.0.0")]
[assembly: AssemblyInformationalVersion("1.2.0+d8dcde9ea5cd799f29003e2283749081b232348a")]
[assembly: AssemblyProduct("DeathRoulette")]
[assembly: AssemblyTitle("DeathRoulette")]
[assembly: AssemblyVersion("1.2.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 DeathRoulette
{
	internal static class Announce
	{
		public static void Death(DeathContext ctx)
		{
			if (Plugin.AnnounceDeaths.Value)
			{
				ServerActions.ShowMessage((MessageType)1, ctx.PlayerName + " has died");
			}
		}

		public static void Effect(DeathContext ctx, RouletteEvent ev, string flavour)
		{
			if (Plugin.AnnounceEffects.Value)
			{
				ServerActions.ShowMessage((MessageType)2, ev.DisplayName);
				ServerActions.ShowMessage((MessageType)1, flavour);
			}
		}

		public static void Manual(string byPlayer, RouletteEvent ev, string flavour, Vector3 at)
		{
			if (Plugin.AnnounceEffects.Value)
			{
				ServerActions.ShowMessage((MessageType)2, ev.DisplayName);
				ServerActions.ShowMessage((MessageType)1, flavour + "  (test fired by " + byPlayer + ")");
			}
		}
	}
	internal static class CommandFile
	{
		private const float PollSeconds = 1f;

		private static float _nextPoll;

		private static string _path;

		private static string _outPath;

		public static void Init(string configDir)
		{
			_path = Path.Combine(configDir, "deathroulette.cmd");
			_outPath = Path.Combine(configDir, "deathroulette.out");
			Plugin.Log.LogInfo((object)("Command file: " + _path));
		}

		public static void Poll()
		{
			if (_path == null || Time.realtimeSinceStartup < _nextPoll)
			{
				return;
			}
			_nextPoll = Time.realtimeSinceStartup + 1f;
			if (!File.Exists(_path))
			{
				return;
			}
			string[] array;
			try
			{
				array = File.ReadAllLines(_path);
				File.Delete(_path);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Could not read the command file: " + ex.Message));
				return;
			}
			List<string> list = new List<string>();
			string[] array2 = array;
			for (int i = 0; i < array2.Length; i++)
			{
				string text = array2[i].Trim();
				if (text.Length != 0 && !text.StartsWith("#"))
				{
					try
					{
						list.AddRange(Execute(text));
					}
					catch (Exception ex2)
					{
						list.Add("'" + text + "' threw: " + ex2.Message);
						Plugin.Log.LogError((object)$"Command '{text}' threw: {ex2}");
					}
				}
			}
			foreach (string item in list)
			{
				Plugin.Log.LogInfo((object)("[cmd] " + item));
			}
			try
			{
				File.WriteAllLines(_outPath, list);
			}
			catch (Exception ex3)
			{
				Plugin.Log.LogWarning((object)("Could not write command output: " + ex3.Message));
			}
		}

		internal static IEnumerable<string> Execute(string line)
		{
			string[] array = line.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
			string text = array[0].ToLowerInvariant();
			string text2 = ((array.Length > 1) ? array[1] : null);
			switch (text)
			{
			case "help":
				yield return "commands: list | status | possible | fire <id> | roll | fx <prefab> | stopraid | reload";
				break;
			case "list":
				foreach (RouletteEvent item in RouletteEvents.Table)
				{
					yield return $"{item.Id,-18} w={item.Weight,-3} [{item.Flavour}] {item.DisplayName}";
				}
				break;
			case "status":
			{
				int num = RouletteEvents.Table.Count((RouletteEvent e) => e.Weight > 0);
				List<PlayerInfo> players = ServerActions.OnlinePlayers();
				yield return "master=" + (Plugin.Enabled.Value ? "on" : "off") + " " + $"events={num}/{RouletteEvents.Table.Count} " + $"cooldown={Plugin.CooldownSeconds.Value}s " + $"online={players.Count}";
				foreach (PlayerInfo item2 in players)
				{
					yield return $"  {item2.m_name} at {ServerActions.PositionOf(item2)}";
				}
				break;
			}
			case "possible":
				foreach (string item3 in ListPossibleRaids())
				{
					yield return item3;
				}
				break;
			case "fx":
				foreach (string item4 in PlayEffect(text2))
				{
					yield return item4;
				}
				break;
			case "stopraid":
				yield return ServerActions.StopEvent() ? "cleared the current raid" : "RandEventSystem is not available";
				break;
			case "reload":
				Plugin.ReloadConfig();
				yield return "config reloaded from disk";
				break;
			case "roll":
				foreach (string item5 in FireOne(null))
				{
					yield return item5;
				}
				break;
			case "fire":
				foreach (string item6 in FireOne(text2))
				{
					yield return item6;
				}
				break;
			default:
				yield return "unknown command '" + text + "'; try help";
				break;
			}
		}

		private static IEnumerable<string> ListPossibleRaids()
		{
			List<KeyValuePair<RandomEvent, Vector3>> list = ServerActions.PossibleRaids();
			if (list.Count == 0)
			{
				yield return "no raid is currently valid (nobody online, or none passes the global-key, biome and base checks)";
				yield break;
			}
			foreach (KeyValuePair<RandomEvent, Vector3> item in list)
			{
				yield return $"{item.Key.m_name,-24} at {item.Value}";
			}
		}

		private static IEnumerable<string> PlayEffect(string prefab)
		{
			if (string.IsNullOrEmpty(prefab))
			{
				yield return "usage: fx <prefabName>  (e.g. fx fx_redlightning_burst)";
				yield break;
			}
			List<PlayerInfo> list = ServerActions.OnlinePlayers();
			if (list.Count == 0)
			{
				yield return "nobody is online to show it to";
				yield break;
			}
			PlayerInfo val = list[0];
			Vector3 val2 = ServerActions.PositionOf(val);
			ServerActions.PlayEffect(prefab, val2);
			yield return $"played '{prefab}' at {val.m_name} {val2}";
		}

		private static IEnumerable<string> FireOne(string id)
		{
			List<PlayerInfo> list = ServerActions.OnlinePlayers();
			if (list.Count == 0)
			{
				yield return "nobody is online; effects would have nothing to act on";
				yield break;
			}
			PlayerInfo val = list[0];
			Vector3 val2 = ServerActions.PositionOf(val);
			DeathContext deathContext = new DeathContext(val.m_name, val2, val.m_characterID, isTest: true);
			if (string.IsNullOrEmpty(id) || id.Equals("random", StringComparison.OrdinalIgnoreCase))
			{
				RouletteEvents.RollAndFire(deathContext);
				yield return "rolled the table (victim stand-in: " + val.m_name + ")";
				yield break;
			}
			RouletteEvent rouletteEvent = RouletteEvents.Find(id);
			if (rouletteEvent == null)
			{
				yield return "no event '" + id + "'; try list";
				yield break;
			}
			string text = null;
			string text2 = null;
			try
			{
				text = rouletteEvent.Fire(deathContext);
			}
			catch (Exception ex)
			{
				text2 = ex.Message;
				Plugin.Log.LogError((object)$"Event '{rouletteEvent.Id}' threw: {ex}");
			}
			if (text2 != null)
			{
				yield return rouletteEvent.Id + " threw: " + text2;
				yield break;
			}
			if (text == null)
			{
				yield return rouletteEvent.Id + " declined (nothing for it to act on)";
				yield break;
			}
			Announce.Manual(val.m_name, rouletteEvent, text, val2);
			yield return "fired " + rouletteEvent.Id + ": " + text;
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	internal static class ConsoleCommands
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ConsoleEvent <0>__Handle;
		}

		private static bool _registered;

		[HarmonyPostfix]
		private static void Postfix()
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			if (!_registered)
			{
				_registered = true;
				object obj = <>O.<0>__Handle;
				if (obj == null)
				{
					ConsoleEvent val = Handle;
					<>O.<0>__Handle = val;
					obj = (object)val;
				}
				new ConsoleCommand("deathroulette", "DeathRoulette admin: dr <list|status|possible|fire <id>|roll|fx <prefab>|stopraid|reload|help>", (ConsoleEvent)obj, true, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
				object obj2 = <>O.<0>__Handle;
				if (obj2 == null)
				{
					ConsoleEvent val2 = Handle;
					<>O.<0>__Handle = val2;
					obj2 = (object)val2;
				}
				new ConsoleCommand("dr", "Alias of deathroulette.", (ConsoleEvent)obj2, true, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
				Plugin.Log.LogInfo((object)"Console commands registered: 'deathroulette' / 'dr'.");
			}
		}

		private static void Handle(ConsoleEventArgs args)
		{
			string text = ((args.Length > 1) ? string.Join(" ", args.Args.Skip(1)) : "help");
			try
			{
				foreach (string item in CommandFile.Execute(text))
				{
					Terminal context = args.Context;
					if (context != null)
					{
						context.AddString(item);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)$"Console command '{text}' threw: {ex}");
				Terminal context2 = args.Context;
				if (context2 != null)
				{
					context2.AddString("DeathRoulette: '" + text + "' threw: " + ex.Message);
				}
			}
		}
	}
	[HarmonyPatch(typeof(ZRoutedRpc), "HandleRoutedRPC")]
	internal static class DeathWatcher
	{
		private static readonly int OnDeathHash = StringExtensionMethods.GetStableHashCode("OnDeath");

		private static readonly int PlayerPrefabHash = StringExtensionMethods.GetStableHashCode("Player");

		private static float _lastFireTime = -99999f;

		[HarmonyPostfix]
		private static void Postfix(RoutedRPCData data)
		{
			//IL_0046: 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)
			//IL_007a: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: 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)
			if (data == null || data.m_methodHash != OnDeathHash || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || ((ZDOID)(ref data.m_targetZDO)).IsNone())
			{
				return;
			}
			ZDOMan instance = ZDOMan.instance;
			ZDO val = ((instance != null) ? instance.GetZDO(data.m_targetZDO) : null);
			if (val == null || val.GetPrefab() != PlayerPrefabHash)
			{
				return;
			}
			string text = val.GetString(ZDOVars.s_playerName, "someone");
			Vector3 position = val.GetPosition();
			if (Plugin.VerboseLogging.Value)
			{
				Plugin.Log.LogInfo((object)$"Death detected: {text} at {position} (zdo {data.m_targetZDO}).");
			}
			RouletteEvents.EnsureDumped();
			DeathContext ctx = new DeathContext(text, position, data.m_targetZDO);
			Announce.Death(ctx);
			if (!Plugin.Enabled.Value)
			{
				return;
			}
			float value = Plugin.CooldownSeconds.Value;
			if (Time.realtimeSinceStartup - _lastFireTime < value)
			{
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)$"Roll skipped for {text}: cooldown ({value}s) still active.");
				}
			}
			else
			{
				_lastFireTime = Time.realtimeSinceStartup;
				RouletteEvents.RollAndFire(ctx);
			}
		}
	}
	internal readonly struct DeathContext
	{
		public readonly string PlayerName;

		public readonly Vector3 Position;

		public readonly ZDOID CharacterId;

		public readonly bool IsTest;

		public DeathContext(string playerName, Vector3 position, ZDOID characterId, bool isTest = false)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			PlayerName = playerName;
			Position = position;
			CharacterId = characterId;
			IsTest = isTest;
		}
	}
	internal static class EffectSpec
	{
		private static readonly Random Rng = new Random();

		public static void Play(string spec, Vector3 pos)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			string[] array = PickVariant(spec);
			for (int i = 0; i < array.Length; i++)
			{
				ServerActions.PlayEffect(array[i], pos);
			}
		}

		public static void PlayAtEveryone(string spec)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			string[] array = PickVariant(spec);
			if (array.Length == 0)
			{
				return;
			}
			foreach (PlayerInfo item in ServerActions.OnlinePlayers())
			{
				Vector3 pos = ServerActions.PositionOf(item);
				string[] array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					ServerActions.PlayEffect(array2[i], pos);
				}
			}
		}

		private static string[] PickVariant(string spec)
		{
			if (string.IsNullOrEmpty(spec))
			{
				return new string[0];
			}
			string[] array = (from v in spec.Split('|')
				select v.Trim() into v
				where v.Length > 0
				select v).ToArray();
			if (array.Length == 0)
			{
				return new string[0];
			}
			return (from p in array[Rng.Next(array.Length)].Split('+')
				select p.Trim() into p
				where p.Length > 0
				select p).ToArray();
		}
	}
	internal static class EffectSustain
	{
		private const float TickSeconds = 2f;

		public static void Run(IReadOnlyList<string> statusEffects, float durationSeconds, ServerActions.Element? damageElement = null, float damagePerTick = 0f)
		{
			Plugin instance = Plugin.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				((MonoBehaviour)instance).StartCoroutine(Loop(statusEffects, durationSeconds, damageElement, damagePerTick));
			}
		}

		private static IEnumerator Loop(IReadOnlyList<string> statusEffects, float duration, ServerActions.Element? element, float damagePerTick)
		{
			float elapsed = 0f;
			WaitForSeconds wait = new WaitForSeconds(2f);
			while (elapsed <= duration)
			{
				foreach (PlayerInfo item in ServerActions.OnlinePlayers())
				{
					foreach (string statusEffect in statusEffects)
					{
						ServerActions.AddStatusEffect(item.m_characterID, statusEffect);
					}
					if (element.HasValue && damagePerTick > 0f)
					{
						ServerActions.DamageElemental(item.m_characterID, element.Value, damagePerTick);
					}
				}
				elapsed += 2f;
				yield return wait;
			}
		}

		public static void SustainNoise(float range, float durationSeconds)
		{
			Plugin instance = Plugin.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				((MonoBehaviour)instance).StartCoroutine(NoiseLoop(range, durationSeconds));
			}
		}

		private static IEnumerator NoiseLoop(float range, float duration)
		{
			float elapsed = 0f;
			WaitForSeconds wait = new WaitForSeconds(2f);
			while (elapsed <= duration)
			{
				foreach (PlayerInfo item in ServerActions.OnlinePlayers())
				{
					ServerActions.AddNoise(item.m_characterID, range);
				}
				elapsed += 2f;
				yield return wait;
			}
		}

		public static void Delay(float seconds, Action action)
		{
			Plugin instance = Plugin.Instance;
			if (!((Object)(object)instance == (Object)null))
			{
				((MonoBehaviour)instance).StartCoroutine(DelayLoop(seconds, action));
			}
		}

		private static IEnumerator DelayLoop(float seconds, Action action)
		{
			yield return (object)new WaitForSeconds(seconds);
			try
			{
				action();
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Delayed action threw: {arg}");
			}
		}
	}
	[BepInPlugin("geckuss.deathroulette", "DeathRoulette", "1.2.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string ModGuid = "geckuss.deathroulette";

		public const string ModName = "DeathRoulette";

		public const string ModVersion = "1.2.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> AnnounceDeaths;

		internal static ConfigEntry<bool> AnnounceEffects;

		internal static ConfigEntry<float> CooldownSeconds;

		internal static ConfigEntry<bool> VerboseLogging;

		private static Plugin _instance;

		private Harmony _harmony;

		internal static Plugin Instance => _instance;

		private void Awake()
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Expected O, but got Unknown
			_instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. When false, deaths are detected but no event fires.");
			AnnounceDeaths = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AnnounceDeaths", true, "Announce who died to everyone. Fires on every death, even when the roulette is disabled or on cooldown.");
			AnnounceEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AnnounceEffects", true, "Announce which event was rolled, and what it did, to everyone.");
			CooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("General", "CooldownSeconds", 30f, "Minimum seconds between rolled events, so a wipe does not fire five raids at once.");
			VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "VerboseLogging", false, "Log every detected death and roll.");
			RouletteEvents.BindConfig(((BaseUnityPlugin)this).Config);
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			CommandFile.Init(Path.GetDirectoryName(((BaseUnityPlugin)this).Config.ConfigFilePath));
			_harmony = new Harmony("geckuss.deathroulette");
			_harmony.PatchAll();
			Log.LogInfo((object)"DeathRoulette 1.2.0 loaded.");
		}

		private void Update()
		{
			CommandFile.Poll();
		}

		internal static void ReloadConfig()
		{
			Plugin instance = _instance;
			if (instance != null)
			{
				((BaseUnityPlugin)instance).Config.Reload();
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal enum Flavour
	{
		Harmless,
		Kind,
		Mean,
		Brutal
	}
	internal sealed class RouletteEvent
	{
		public string Id;

		public string DisplayName;

		public Flavour Flavour;

		public int DefaultWeight;

		public string Description;

		public Func<DeathContext, string> Fire;

		internal ConfigEntry<int> WeightConfig;

		public int Weight => WeightConfig?.Value ?? DefaultWeight;
	}
	internal static class RouletteEvents
	{
		private sealed class BossEntry
		{
			public readonly string Key;

			public readonly string Altar;

			public readonly string Prefab;

			public readonly string Label;

			public readonly string MusicEvent;

			public BossEntry(string key, string altar, string prefab, string label, string musicEvent)
			{
				Key = key;
				Altar = altar;
				Prefab = prefab;
				Label = label;
				MusicEvent = musicEvent;
			}
		}

		private static readonly Random Rng = new Random();

		private static string _lastFiredId;

		private static bool _dumped;

		private const string DefaultRaids = "";

		private static ConfigEntry<string> _raidPool;

		private static ConfigEntry<bool> _gateRaids;

		private static ConfigEntry<string> _thunderFx;

		private static ConfigEntry<string> _omenFx;

		private static ConfigEntry<string> _lamentFx;

		private static ConfigEntry<float> _thunderDamage;

		private static ConfigEntry<bool> _summonBoss;

		private static ConfigEntry<string> _adrenalineBuff;

		private static readonly string[] UngatedFallback = new string[9] { "army_eikthyr", "army_theelder", "foresttrolls", "blobs", "skeletons", "surtlings", "wolves", "bats", "ghosts" };

		private static readonly string[] NastyEffects = new string[5] { "Burning", "Frost", "Poison", "Wet", "Smoked" };

		private static readonly string[] ForsakenPowers = new string[7] { "GP_Eikthyr", "GP_TheElder", "GP_Bonemass", "GP_Moder", "GP_Yagluth", "GP_Queen", "GP_Fader" };

		private const string DefaultThunderFx = "fx_redlightning_burst+fx_chainlightning_hit+fx_lightningweapon_hit|fx_JotunWitch_LightningBolt_Explosion+fx_himminafl_aoe";

		private static readonly string[] Windfall = new string[10] { "Resin", "Wood", "Stone", "Flint", "Feathers", "Mushroom", "Raspberry", "Honey", "Coins", "BoneFragments" };

		private static readonly string[] SwarmCreatures = new string[5] { "Greyling", "Neck", "Boar", "Skeleton", "Greydwarf" };

		private static readonly (string Location, string Label, PinType Pin)[] Landmarks = new(string, string, PinType)[10]
		{
			("Vendor_BlackForest", "Haldor", (PinType)6),
			("Eikthyrnir", "Eikthyr", (PinType)9),
			("GDKing", "The Elder", (PinType)9),
			("Bonemass", "Bonemass", (PinType)9),
			("Dragonqueen", "Moder", (PinType)9),
			("GoblinKing", "Yagluth", (PinType)9),
			("Hildir_camp", "Hildir", (PinType)6),
			("Crypt2", "Burial Chamber", (PinType)3),
			("SunkenCrypt4", "Sunken Crypt", (PinType)3),
			("MountainCave02", "Frost Cave", (PinType)3)
		};

		private static readonly BossEntry[] Bosses = new BossEntry[5]
		{
			new BossEntry("defeated_eikthyr", "Eikthyrnir", "Eikthyr", "Eikthyr", "boss_eikthyr"),
			new BossEntry("defeated_gdking", "GDKing", "gd_king", "The Elder", "boss_gdking"),
			new BossEntry("defeated_bonemass", "Bonemass", "Bonemass", "Bonemass", "boss_bonemass"),
			new BossEntry("defeated_dragon", "Dragonqueen", "Dragon", "Moder", "boss_moder"),
			new BossEntry("defeated_goblinking", "GoblinKing", "GoblinKing", "Yagluth", "boss_goblinking")
		};

		private static readonly string[] PhantomWords = new string[8] { "MOURNED", "NOTED", "TYPICAL", "AGAIN?", "SKILL ISSUE", "VALHALLA", "OOPS", "RECORDED" };

		private const string DefaultOmenFx = "sfx_frostfoundry_activate";

		private const string DefaultLamentFx = "sfx_gjall_alerted+sfx_gjall_idle_vocals";

		internal static readonly List<RouletteEvent> Table = new List<RouletteEvent>
		{
			new RouletteEvent
			{
				Id = "taunt",
				DisplayName = "Odin's Indifference",
				Flavour = Flavour.Harmless,
				DefaultWeight = 9,
				Description = "Odin passes comment. Nothing else happens.",
				Fire = delegate
				{
					string[] array = new string[4] { "Odin was not impressed.", "Gone to feast early.", "The Valkyries looked, and kept walking.", "The ground was harder than expected." };
					return array[Rng.Next(array.Length)];
				}
			},
			new RouletteEvent
			{
				Id = "thunderclap",
				DisplayName = "Thunderclap",
				Flavour = Flavour.Mean,
				DefaultWeight = 7,
				Description = "Lightning strikes every player, for a little damage.",
				Fire = delegate
				{
					//IL_0037: Unknown result type (might be due to invalid IL or missing references)
					//IL_003c: Unknown result type (might be due to invalid IL or missing references)
					EffectSpec.PlayAtEveryone(ThunderFx);
					float num = _thunderDamage?.Value ?? 10f;
					if (num > 0f)
					{
						foreach (PlayerInfo item in ServerActions.OnlinePlayers())
						{
							ServerActions.DamageElemental(item.m_characterID, ServerActions.Element.Lightning, num);
						}
					}
					return "The sky cracks, and it finds everyone.";
				}
			},
			new RouletteEvent
			{
				Id = "bossstone_omen",
				DisplayName = "Ancient Omen",
				Flavour = Flavour.Harmless,
				DefaultWeight = 7,
				Description = "A boss-stone activation effect fires at everyone's feet. Pure theatre.",
				Fire = delegate
				{
					EffectSpec.PlayAtEveryone(_omenFx?.Value ?? "sfx_frostfoundry_activate");
					return "Something ancient noticed.";
				}
			},
			new RouletteEvent
			{
				Id = "gjall_lament",
				DisplayName = "Lament",
				Flavour = Flavour.Harmless,
				DefaultWeight = 7,
				Description = "A gjall's taunt echoes over every player. Unsettling, harmless.",
				Fire = delegate
				{
					EffectSpec.PlayAtEveryone(_lamentFx?.Value ?? "sfx_gjall_alerted+sfx_gjall_idle_vocals");
					return "A mourning cry answers from far off.";
				}
			},
			new RouletteEvent
			{
				Id = "moment_of_silence",
				DisplayName = "Moment of Silence",
				Flavour = Flavour.Harmless,
				DefaultWeight = 7,
				Description = "Everyone's animation hitches for a moment.",
				Fire = delegate
				{
					//IL_000f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0014: Unknown result type (might be due to invalid IL or missing references)
					foreach (PlayerInfo item2 in ServerActions.OnlinePlayers())
					{
						ServerActions.FreezeFrame(item2.m_characterID, 0.6f);
					}
					return "Midgard pauses.";
				}
			},
			new RouletteEvent
			{
				Id = "forsaken_gift",
				DisplayName = "Forsaken Gift",
				Flavour = Flavour.Kind,
				DefaultWeight = 7,
				Description = "A random forsaken power is granted to everyone.",
				Fire = delegate
				{
					string text = ForsakenPowers[Rng.Next(ForsakenPowers.Length)];
					ServerActions.AddStatusEffectToAll(text);
					return "A boon is granted to all: " + text + ".";
				}
			},
			new RouletteEvent
			{
				Id = "rested",
				DisplayName = "Granted Rest",
				Flavour = Flavour.Kind,
				DefaultWeight = 4,
				Description = "Rested buff for everyone.",
				Fire = delegate
				{
					ServerActions.AddStatusEffectToAll("Rested");
					return "The gods grant rest to all.";
				}
			},
			new RouletteEvent
			{
				Id = "second_wind",
				DisplayName = "Second Wind",
				Flavour = Flavour.Kind,
				DefaultWeight = 6,
				Description = "Every surviving player is healed to full.",
				Fire = delegate(DeathContext ctx)
				{
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0021: Unknown result type (might be due to invalid IL or missing references)
					List<PlayerInfo> list = Survivors(ctx);
					if (list.Count == 0)
					{
						return (string)null;
					}
					foreach (PlayerInfo item3 in list)
					{
						ServerActions.Heal(item3.m_characterID, 9999f);
					}
					return "Wounds close on the living.";
				}
			},
			new RouletteEvent
			{
				Id = "dawn_mercy",
				DisplayName = "Mercy of Dawn",
				Flavour = Flavour.Kind,
				DefaultWeight = 4,
				Description = "Time skips to the next morning.",
				Fire = (DeathContext ctx) => (!ServerActions.SkipToMorning()) ? null : "The night ends early, out of pity."
			},
			new RouletteEvent
			{
				Id = "shared_pain",
				DisplayName = "Shared Pain",
				Flavour = Flavour.Mean,
				DefaultWeight = 5,
				Description = "A random harmful status effect hits everyone.",
				Fire = delegate
				{
					string text = NastyEffects[Rng.Next(NastyEffects.Length)];
					ServerActions.AddStatusEffectToAll(text);
					return "The gods share the pain: " + text + ".";
				}
			},
			new RouletteEvent
			{
				Id = "soaked",
				DisplayName = "Cold Rain",
				Flavour = Flavour.Mean,
				DefaultWeight = 3,
				Description = "A cold downpour: Wet and Cold on everyone, with a splash underfoot.",
				Fire = delegate
				{
					//IL_000f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0014: Unknown result type (might be due to invalid IL or missing references)
					//IL_0015: Unknown result type (might be due to invalid IL or missing references)
					//IL_001a: Unknown result type (might be due to invalid IL or missing references)
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					//IL_002b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0031: Unknown result type (might be due to invalid IL or missing references)
					//IL_0032: Unknown result type (might be due to invalid IL or missing references)
					//IL_0042: Unknown result type (might be due to invalid IL or missing references)
					foreach (PlayerInfo item4 in ServerActions.OnlinePlayers())
					{
						Vector3 pos = ServerActions.PositionOf(item4);
						ServerActions.PlayEffect("vfx_watersplash_longship", pos);
						ServerActions.PlayEffect("vfx_Wet", pos);
						ServerActions.AddStatusEffect(item4.m_characterID, "Wet");
						ServerActions.AddStatusEffect(item4.m_characterID, "Cold");
					}
					return "A cold rain falls on everyone.";
				}
			},
			new RouletteEvent
			{
				Id = "blood_tax",
				DisplayName = "Blood Tax",
				Flavour = Flavour.Mean,
				DefaultWeight = 5,
				Description = "Survivors lose up to a quarter of current health. Never lethal.",
				Fire = delegate(DeathContext ctx)
				{
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0021: Unknown result type (might be due to invalid IL or missing references)
					List<PlayerInfo> list = Survivors(ctx);
					if (list.Count == 0)
					{
						return (string)null;
					}
					foreach (PlayerInfo item5 in list)
					{
						ServerActions.DamageCapped(item5.m_characterID, 40f);
					}
					return "The debt is billed to the living.";
				}
			},
			new RouletteEvent
			{
				Id = "stagger_all",
				DisplayName = "Lurch",
				Flavour = Flavour.Mean,
				DefaultWeight = 5,
				Description = "Everyone is staggered, losing control briefly.",
				Fire = delegate
				{
					//IL_000f: Unknown result type (might be due to invalid IL or missing references)
					//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)
					foreach (PlayerInfo item6 in ServerActions.OnlinePlayers())
					{
						ServerActions.Stagger(item6.m_characterID, RandomHorizontal());
					}
					return "The ground lurches underfoot.";
				}
			},
			new RouletteEvent
			{
				Id = "loud_grief",
				DisplayName = "Loud Grief",
				Flavour = Flavour.Mean,
				DefaultWeight = 4,
				Description = "Everyone becomes loud for 20 seconds, drawing creatures in.",
				Fire = delegate
				{
					if (ServerActions.OnlinePlayers().Count == 0)
					{
						return (string)null;
					}
					EffectSustain.SustainNoise(100f, 20f);
					return "Grief carries further than it should.";
				}
			},
			new RouletteEvent
			{
				Id = "raid",
				DisplayName = "Raid",
				Flavour = Flavour.Brutal,
				DefaultWeight = 10,
				Description = "A real raid: music, banner, spawners. Progression-gated by default.",
				Fire = FireRaid
			},
			new RouletteEvent
			{
				Id = "summon_mourners",
				DisplayName = "Summoned Mourners",
				Flavour = Flavour.Brutal,
				DefaultWeight = 5,
				Description = "Every survivor is teleported to the corpse, wherever it is.",
				Fire = delegate(DeathContext ctx)
				{
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0021: Unknown result type (might be due to invalid IL or missing references)
					//IL_0027: Unknown result type (might be due to invalid IL or missing references)
					List<PlayerInfo> list = Survivors(ctx);
					if (list.Count == 0)
					{
						return (string)null;
					}
					foreach (PlayerInfo item7 in list)
					{
						ServerActions.TeleportTo(item7.m_characterID, ctx.Position);
					}
					return "All of Midgard is summoned to mourn.";
				}
			},
			new RouletteEvent
			{
				Id = "scatter",
				DisplayName = "Scattered",
				Flavour = Flavour.Brutal,
				DefaultWeight = 7,
				Description = "Every survivor is thrown a short random distance.",
				Fire = delegate(DeathContext ctx)
				{
					//IL_001c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0021: Unknown result type (might be due to invalid IL or missing references)
					//IL_0035: Unknown result type (might be due to invalid IL or missing references)
					//IL_003a: Unknown result type (might be due to invalid IL or missing references)
					//IL_003b: Unknown result type (might be due to invalid IL or missing references)
					//IL_003c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0041: Unknown result type (might be due to invalid IL or missing references)
					//IL_0042: Unknown result type (might be due to invalid IL or missing references)
					//IL_0047: 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_0049: Unknown result type (might be due to invalid IL or missing references)
					List<PlayerInfo> list = Survivors(ctx);
					if (list.Count == 0)
					{
						return (string)null;
					}
					foreach (PlayerInfo item8 in list)
					{
						Vector3 val = RandomHorizontal() * Random.Range(20f, 60f);
						ServerActions.TeleportTo(pos: ServerActions.PositionOf(item8) + val, target: item8.m_characterID);
					}
					return "The living are scattered.";
				}
			},
			new RouletteEvent
			{
				Id = "grave_guardian",
				DisplayName = "Grave Guardian",
				Flavour = Flavour.Brutal,
				DefaultWeight = 7,
				Description = "One creature is spawned on the corpse to guard it.",
				Fire = delegate(DeathContext ctx)
				{
					//IL_0041: Unknown result type (might be due to invalid IL or missing references)
					//IL_0055: Unknown result type (might be due to invalid IL or missing references)
					string[] array = new string[5] { "Draugr", "Greydwarf_Elite", "Skeleton", "Wraith", "Ghost" };
					string text = array[Rng.Next(array.Length)];
					if (!ServerActions.SpawnNetworked(text, ctx.Position))
					{
						return (string)null;
					}
					ServerActions.PlayEffect("fx_Lightning_red", ctx.Position);
					return "Something now guards the grave: " + text + ".";
				}
			},
			new RouletteEvent
			{
				Id = "corpse_run",
				DisplayName = "Called to the Grave",
				Flavour = Flavour.Kind,
				DefaultWeight = 5,
				Description = "Ten seconds after dying, the fallen player is pulled back to their grave.",
				Fire = delegate(DeathContext ctx)
				{
					//IL_000f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0014: Unknown result type (might be due to invalid IL or missing references)
					//IL_0022: Unknown result type (might be due to invalid IL or missing references)
					//IL_0027: Unknown result type (might be due to invalid IL or missing references)
					//IL_002e: Unknown result type (might be due to invalid IL or missing references)
					//IL_0033: Unknown result type (might be due to invalid IL or missing references)
					if (!ctx.IsTest)
					{
						ZDOID characterId = ctx.CharacterId;
						if (!((ZDOID)(ref characterId)).IsNone())
						{
							ZDOID who = ctx.CharacterId;
							Vector3 grave = ctx.Position;
							EffectSustain.Delay(10f, delegate
							{
								//IL_0001: Unknown result type (might be due to invalid IL or missing references)
								//IL_0007: Unknown result type (might be due to invalid IL or missing references)
								//IL_0018: Unknown result type (might be due to invalid IL or missing references)
								ServerActions.TeleportTo(who, grave);
								ServerActions.PlayEffect("vfx_spawn", grave);
							});
							return "The grave calls its owner back.";
						}
					}
					return (string)null;
				}
			},
			new RouletteEvent
			{
				Id = "revealed_path",
				DisplayName = "A Path Revealed",
				Flavour = Flavour.Kind,
				DefaultWeight = 4,
				Description = "Pins the nearest landmark on each player's map and turns them to face it.",
				Fire = delegate
				{
					//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_0040: Unknown result type (might be due to invalid IL or missing references)
					//IL_0042: Unknown result type (might be due to invalid IL or missing references)
					//IL_005a: 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_0068: Unknown result type (might be due to invalid IL or missing references)
					List<PlayerInfo> list = ServerActions.OnlinePlayers();
					if (list.Count == 0)
					{
						return (string)null;
					}
					(string, string, PinType) tuple = Landmarks[Rng.Next(Landmarks.Length)];
					int num = 0;
					foreach (PlayerInfo item9 in list)
					{
						long num2 = ServerActions.OwnerOf(item9.m_characterID);
						if (num2 != 0L && ServerActions.RevealLocation(num2, tuple.Item1, ServerActions.PositionOf(item9), tuple.Item2, tuple.Item3))
						{
							num++;
						}
					}
					return (num != 0) ? ("The dead whisper directions: " + tuple.Item2 + ".") : null;
				}
			},
			new RouletteEvent
			{
				Id = "windfall",
				DisplayName = "Windfall",
				Flavour = Flavour.Kind,
				DefaultWeight = 7,
				Description = "Scatters a pile of materials on the ground at the corpse.",
				Fire = delegate(DeathContext ctx)
				{
					//IL_002c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0031: Unknown result type (might be due to invalid IL or missing references)
					//IL_004b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0050: Unknown result type (might be due to invalid IL or missing references)
					//IL_0055: 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_006c: Unknown result type (might be due to invalid IL or missing references)
					string text = Windfall[Rng.Next(Windfall.Length)];
					int num = Rng.Next(3, 7);
					int num2 = 0;
					for (int i = 0; i < num; i++)
					{
						Vector3 pos = ctx.Position + RandomHorizontal() * (float)(Rng.NextDouble() * 2.0) + Vector3.up * 0.5f;
						if (ServerActions.SpawnNetworked(text, pos))
						{
							num2++;
						}
					}
					return (num2 != 0) ? $"The ground gives up {num2} x {text}." : null;
				}
			},
			new RouletteEvent
			{
				Id = "gods_relent",
				DisplayName = "The Gods Relent",
				Flavour = Flavour.Kind,
				DefaultWeight = 4,
				Description = "Ends the raid that is currently running. Declines when there is none.",
				Fire = delegate
				{
					if (!ServerActions.HaveActiveRaid())
					{
						return (string)null;
					}
					return (!ServerActions.StopEvent()) ? null : "The attack loses interest and melts away.";
				}
			},
			new RouletteEvent
			{
				Id = "phantom_numbers",
				DisplayName = "Phantom Numbers",
				Flavour = Flavour.Harmless,
				DefaultWeight = 6,
				Description = "Floating text appears over every player. Purely cosmetic.",
				Fire = delegate
				{
					//IL_0033: Unknown result type (might be due to invalid IL or missing references)
					//IL_0038: Unknown result type (might be due to invalid IL or missing references)
					//IL_003d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0047: Unknown result type (might be due to invalid IL or missing references)
					//IL_004c: Unknown result type (might be due to invalid IL or missing references)
					List<PlayerInfo> list = ServerActions.OnlinePlayers();
					if (list.Count == 0)
					{
						return (string)null;
					}
					string text = PhantomWords[Rng.Next(PhantomWords.Length)];
					foreach (PlayerInfo item10 in list)
					{
						ServerActions.FloatingText(ServerActions.PositionOf(item10) + Vector3.up * 1.8f, text, (TextType)7);
					}
					return "The air itself keeps score.";
				}
			},
			new RouletteEvent
			{
				Id = "deep_chill",
				DisplayName = "Deep Chill",
				Flavour = Flavour.Mean,
				DefaultWeight = 4,
				Description = "Cold and Freezing on everyone for three minutes, with a steady frost bite.",
				Fire = delegate
				{
					if (ServerActions.OnlinePlayers().Count == 0)
					{
						return (string)null;
					}
					EffectSustain.Run(new string[2] { "Cold", "Freezing" }, 180f, ServerActions.Element.Frost, 3f);
					return "The cold comes for the living too.";
				}
			},
			new RouletteEvent
			{
				Id = "tar_soaked",
				DisplayName = "Tar-Soaked",
				Flavour = Flavour.Mean,
				DefaultWeight = 4,
				Description = "Tared and Slimed on everyone for 20 seconds: slow and clumsy.",
				Fire = delegate
				{
					if (ServerActions.OnlinePlayers().Count == 0)
					{
						return (string)null;
					}
					EffectSustain.Run(new string[2] { "Tared", "Slimed" }, 20f);
					return "Something clinging and black coats every boot.";
				}
			},
			new RouletteEvent
			{
				Id = "swarm",
				DisplayName = "Swarm",
				Flavour = Flavour.Brutal,
				DefaultWeight = 8,
				Description = "Spawns a handful of small creatures on the corpse.",
				Fire = delegate(DeathContext ctx)
				{
					//IL_002c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0031: Unknown result type (might be due to invalid IL or missing references)
					//IL_0055: Unknown result type (might be due to invalid IL or missing references)
					//IL_005a: 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_0062: 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)
					string text = SwarmCreatures[Rng.Next(SwarmCreatures.Length)];
					int num = Rng.Next(3, 6);
					int num2 = 0;
					for (int i = 0; i < num; i++)
					{
						Vector3 pos = ctx.Position + RandomHorizontal() * (float)(2.0 + Rng.NextDouble() * 3.0);
						if (ServerActions.SpawnNetworked(text, pos))
						{
							num2++;
						}
					}
					if (num2 == 0)
					{
						return (string)null;
					}
					ServerActions.PlayEffect("vfx_spawn_large", ctx.Position);
					return $"{num2} x {text} crawl out to meet the body.";
				}
			},
			new RouletteEvent
			{
				Id = "swap_places",
				DisplayName = "Swapped",
				Flavour = Flavour.Brutal,
				DefaultWeight = 3,
				Description = "Two random players trade positions. Needs two online.",
				Fire = delegate
				{
					//IL_003f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0046: Unknown result type (might be due to invalid IL or missing references)
					//IL_004b: Unknown result type (might be due to invalid IL or missing references)
					//IL_004c: Unknown result type (might be due to invalid IL or missing references)
					//IL_004d: 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_0054: Unknown result type (might be due to invalid IL or missing references)
					//IL_0055: Unknown result type (might be due to invalid IL or missing references)
					//IL_005a: Unknown result type (might be due to invalid IL or missing references)
					//IL_005c: Unknown result type (might be due to invalid IL or missing references)
					//IL_005d: Unknown result type (might be due to invalid IL or missing references)
					//IL_0062: Unknown result type (might be due to invalid IL or missing references)
					//IL_006a: 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_0082: Unknown result type (might be due to invalid IL or missing references)
					List<PlayerInfo> list = ServerActions.OnlinePlayers();
					if (list.Count < 2)
					{
						return (string)null;
					}
					int num = Rng.Next(list.Count);
					int num2 = Rng.Next(list.Count - 1);
					if (num2 >= num)
					{
						num2++;
					}
					PlayerInfo val = list[num];
					PlayerInfo val2 = list[num2];
					Vector3 pos = ServerActions.PositionOf(val);
					ServerActions.TeleportTo(pos: ServerActions.PositionOf(val2), target: val.m_characterID);
					ServerActions.TeleportTo(val2.m_characterID, pos);
					return val.m_name + " and " + val2.m_name + " wake up somewhere unfamiliar.";
				}
			},
			new RouletteEvent
			{
				Id = "feather_fall",
				DisplayName = "Feather Fall",
				Flavour = Flavour.Kind,
				DefaultWeight = 4,
				Description = "Slow Fall on everyone for five minutes: no fall damage.",
				Fire = delegate
				{
					if (ServerActions.OnlinePlayers().Count == 0)
					{
						return (string)null;
					}
					EffectSustain.Run(new string[1] { "SlowFall" }, 300f);
					return "Everyone is suddenly very light.";
				}
			},
			new RouletteEvent
			{
				Id = "mistveil",
				DisplayName = "Mistveil",
				Flavour = Flavour.Kind,
				DefaultWeight = 3,
				Description = "Demister on everyone for five minutes: the mist parts.",
				Fire = delegate
				{
					if (ServerActions.OnlinePlayers().Count == 0)
					{
						return (string)null;
					}
					EffectSustain.Run(new string[1] { "Demister" }, 300f);
					return "The mist draws back.";
				}
			},
			new RouletteEvent
			{
				Id = "sheltered",
				DisplayName = "Sheltered",
				Flavour = Flavour.Kind,
				DefaultWeight = 3,
				Description = "Shelter and Campfire comfort on everyone for three minutes.",
				Fire = delegate
				{
					if (ServerActions.OnlinePlayers().Count == 0)
					{
						return (string)null;
					}
					EffectSustain.Run(new string[2] { "Shelter", "CampFire" }, 180f);
					return "A warmth with no fire behind it.";
				}
			},
			new RouletteEvent
			{
				Id = "adrenaline_rush",
				DisplayName = "Adrenaline",
				Flavour = Flavour.Kind,
				DefaultWeight = 4,
				Description = "A surge for everyone: full heal, a stamina-regen buff, and Ashlands adrenaline.",
				Fire = delegate
				{
					//IL_001b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					//IL_0021: Unknown result type (might be due to invalid IL or missing references)
					//IL_0046: Unknown result type (might be due to invalid IL or missing references)
					//IL_0047: 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)
					List<PlayerInfo> list = ServerActions.OnlinePlayers();
					if (list.Count == 0)
					{
						return (string)null;
					}
					foreach (PlayerInfo item11 in list)
					{
						ServerActions.AddStatusEffect(item11.m_characterID, _adrenalineBuff?.Value ?? "StaminaMedium");
						ServerActions.Heal(item11.m_characterID, 25f);
						ServerActions.AddAdrenaline(item11.m_characterID, 30f);
					}
					return "Hearts hammer. Second wind for everyone.";
				}
			},
			new RouletteEvent
			{
				Id = "pyre",
				DisplayName = "Pyre",
				Flavour = Flavour.Mean,
				DefaultWeight = 4,
				Description = "Burning and fire damage on everyone for 20 seconds, with flames underfoot.",
				Fire = delegate
				{
					//IL_001b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					//IL_0026: Unknown result type (might be due to invalid IL or missing references)
					//IL_0027: Unknown result type (might be due to invalid IL or missing references)
					List<PlayerInfo> list = ServerActions.OnlinePlayers();
					if (list.Count == 0)
					{
						return (string)null;
					}
					foreach (PlayerInfo item12 in list)
					{
						ServerActions.PlayEffect("fx_fireskeleton_nova", ServerActions.PositionOf(item12));
					}
					EffectSustain.Run(new string[1] { "Burning" }, 20f, ServerActions.Element.Fire, 6f);
					return "The pyre is lit under everyone at once.";
				}
			},
			new RouletteEvent
			{
				Id = "plague",
				DisplayName = "Plague",
				Flavour = Flavour.Mean,
				DefaultWeight = 4,
				Description = "Poison and poison damage on everyone for 20 seconds.",
				Fire = delegate
				{
					//IL_001b: Unknown result type (might be due to invalid IL or missing references)
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					//IL_0026: Unknown result type (might be due to invalid IL or missing references)
					//IL_0027: Unknown result type (might be due to invalid IL or missing references)
					List<PlayerInfo> list = ServerActions.OnlinePlayers();
					if (list.Count == 0)
					{
						return (string)null;
					}
					foreach (PlayerInfo item13 in list)
					{
						ServerActions.PlayEffect("vfx_BombBlob_explode_poison", ServerActions.PositionOf(item13));
					}
					EffectSustain.Run(new string[1] { "Poison" }, 20f, ServerActions.Element.Poison, 5f);
					return "Something rotten spreads from the body.";
				}
			},
			new RouletteEvent
			{
				Id = "smoked_out",
				DisplayName = "Smoked Out",
				Flavour = Flavour.Mean,
				DefaultWeight = 3,
				Description = "Smoked on everyone for three minutes: no resting until it clears.",
				Fire = delegate
				{
					if (ServerActions.OnlinePlayers().Count == 0)
					{
						return (string)null;
					}
					EffectSustain.Run(new string[1] { "Smoked" }, 180f);
					return "Smoke finds every pair of lungs.";
				}
			},
			new RouletteEvent
			{
				Id = "pilgrimage",
				DisplayName = "Pilgrimage",
				Flavour = Flavour.Brutal,
				DefaultWeight = 1,
				Description = "Sends everyone to the altar of the last boss the world defeated, and wakes it up again. The single most dangerous event here.",
				Fire = delegate(DeathContext ctx)
				{
					//IL_0050: Unknown result type (might be due to invalid IL or missing references)
					//IL_006c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0071: Unknown result type (might be due to invalid IL or missing references)
					//IL_0076: Unknown result type (might be due to invalid IL or missing references)
					//IL_0077: Unknown result type (might be due to invalid IL or missing references)
					//IL_009b: Unknown result type (might be due to invalid IL or missing references)
					//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
					//IL_00df: Unknown result type (might be due to invalid IL or missing references)
					//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
					//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
					//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
					//IL_0102: Unknown result type (might be due to invalid IL or missing references)
					//IL_010e: Unknown result type (might be due to invalid IL or missing references)
					List<PlayerInfo> list = ServerActions.OnlinePlayers();
					if (list.Count == 0)
					{
						return (string)null;
					}
					BossEntry bossEntry = null;
					BossEntry[] bosses = Bosses;
					foreach (BossEntry bossEntry2 in bosses)
					{
						if (ServerActions.HasGlobalKey(bossEntry2.Key))
						{
							bossEntry = bossEntry2;
						}
					}
					if (bossEntry == null)
					{
						return (string)null;
					}
					if (!ServerActions.FindLocation(bossEntry.Altar, ctx.Position, out var pos))
					{
						return (string)null;
					}
					foreach (PlayerInfo item14 in list)
					{
						ServerActions.TeleportTo(item14.m_characterID, pos + RandomHorizontal() * (float)(2.0 + Rng.NextDouble() * 4.0));
					}
					bool flag = false;
					if (_summonBoss == null || _summonBoss.Value)
					{
						flag = ServerActions.SpawnNetworked(bossEntry.Prefab, pos + Vector3.up * 1f);
						if (flag)
						{
							ServerActions.PlayEffect("vfx_spawn_large", pos);
							ServerActions.StartEvent(bossEntry.MusicEvent, pos);
						}
					}
					return (!flag) ? ("Everyone is summoned to the altar of " + bossEntry.Label + ".") : (bossEntry.Label + " is dragged back to its altar, and so is everyone else.");
				}
			}
		};

		private static List<string> RaidPool => (from s in (_raidPool?.Value ?? "").Split(',')
			select s.Trim() into s
			where s.Length > 0
			select s).ToList();

		internal static string ThunderFx => _thunderFx?.Value ?? "fx_redlightning_burst+fx_chainlightning_hit+fx_lightningweapon_hit|fx_JotunWitch_LightningBolt_Explosion+fx_himminafl_aoe";

		private static string FireRaid(DeathContext ctx)
		{
			//IL_00b9: 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)
			RandEventSystem res = RandEventSystem.instance;
			if ((Object)(object)res == (Object)null)
			{
				return null;
			}
			List<string> pool = RaidPool;
			if (_gateRaids == null || _gateRaids.Value)
			{
				List<KeyValuePair<RandomEvent, Vector3>> list = ServerActions.PossibleRaids();
				if (pool.Count > 0)
				{
					list = list.Where((KeyValuePair<RandomEvent, Vector3> kv) => pool.Contains(kv.Key.m_name)).ToList();
				}
				if (list.Count == 0)
				{
					if (Plugin.VerboseLogging.Value)
					{
						Plugin.Log.LogInfo((object)"No raid is currently valid for anyone online.");
					}
					return null;
				}
				KeyValuePair<RandomEvent, Vector3> keyValuePair = list[Rng.Next(list.Count)];
				if (!ServerActions.StartEvent(keyValuePair.Key.m_name, keyValuePair.Value))
				{
					return null;
				}
				return "The noise drew something: " + keyValuePair.Key.m_name + ".";
			}
			List<string> list2 = ((pool.Count > 0) ? pool : UngatedFallback.ToList()).Where((string n) => res.HaveEvent(n)).ToList();
			if (list2.Count == 0)
			{
				return null;
			}
			string text = list2[Rng.Next(list2.Count)];
			if (!ServerActions.StartEvent(text, ctx.Position))
			{
				return null;
			}
			return "The noise drew something: " + text + ".";
		}

		public static void BindConfig(ConfigFile config)
		{
			_gateRaids = config.Bind<bool>("Raids", "UseVanillaGating", true, "Only start raids vanilla considers valid right now, at a position it picks. That respects progression (global keys), biome and base checks, so an early base cannot be handed a late-game raid. Set false to force one from Pool at the corpse regardless of progress.");
			_thunderFx = config.Bind<string>("Effects", "Thunderclap", "fx_redlightning_burst+fx_chainlightning_hit+fx_lightningweapon_hit|fx_JotunWitch_LightningBolt_Explosion+fx_himminafl_aoe", "Effects for the thunderclap event. Variants separated by '|', prefabs within a variant by '+'. One variant is picked at random and all its prefabs play together at the same spot. Audition any of them live with: dr.sh fx <name> [more names...] -- reference/effect-prefab-names.txt lists all 1892. Note SpawnObject does a bare Instantiate with no setup, so a prefab whose visual needs runtime configuration (line-renderer endpoints, an Aoe or Projectile owner) will spawn and sound right while rendering wrong; fx_Lightning is exactly that.");
			_omenFx = config.Bind<string>("Effects", "AncientOmen", "sfx_frostfoundry_activate", "Effects for the ancient omen event, played at every player. Variants separated by '|', prefabs within a variant by '+'. One variant is picked at random and all its prefabs play together at the same spot. Audition any of them live with: dr.sh fx <name> [more names...] -- reference/effect-prefab-names.txt lists all 1892. Note SpawnObject does a bare Instantiate with no setup, so a prefab whose visual needs runtime configuration (line-renderer endpoints, an Aoe or Projectile owner) will spawn and sound right while rendering wrong; fx_Lightning is exactly that.");
			_lamentFx = config.Bind<string>("Effects", "Lament", "sfx_gjall_alerted+sfx_gjall_idle_vocals", "Effects for the lament event, played at every player. Variants separated by '|', prefabs within a variant by '+'. One variant is picked at random and all its prefabs play together at the same spot. Audition any of them live with: dr.sh fx <name> [more names...] -- reference/effect-prefab-names.txt lists all 1892. Note SpawnObject does a bare Instantiate with no setup, so a prefab whose visual needs runtime configuration (line-renderer endpoints, an Aoe or Projectile owner) will spawn and sound right while rendering wrong; fx_Lightning is exactly that.");
			_summonBoss = config.Bind<bool>("Events", "PilgrimageSummonsBoss", true, "Whether the pilgrimage event also respawns the boss at its altar. This can very easily wipe everyone online and leave the gear at an altar far from home. Set false to keep the mass teleport without the boss.");
			_thunderDamage = config.Bind<float>("Effects", "ThunderclapDamage", 10f, "Lightning damage the thunderclap deals to each player. Capped at a quarter of current health, so it can never be the killing blow. 0 disables the damage.");
			_adrenalineBuff = config.Bind<string>("Effects", "AdrenalineBuff", "StaminaMedium", "Status effect the adrenaline event grants for its stamina-regen buff. Must be a vanilla status effect name resolvable by the client's ObjectDB.");
			_raidPool = config.Bind<string>("Raids", "Pool", "", "Comma-separated raid event names the 'raid' event may pick from. Unknown or disabled names are skipped. Leave EMPTY (the default) to allow whatever vanilla currently permits, which is usually what you want with UseVanillaGating on. Boss summons (boss_*, hildirboss1..3) are never offered: vanilla marks them m_random = false and the gating honours that.");
			foreach (RouletteEvent item in Table)
			{
				item.WeightConfig = config.Bind<int>("Weights", item.Id, item.DefaultWeight, $"[{item.Flavour}] {item.Description} Relative weight; 0 disables it.");
			}
		}

		public static RouletteEvent Find(string id)
		{
			return Table.FirstOrDefault((RouletteEvent e) => string.Equals(e.Id, id, StringComparison.OrdinalIgnoreCase));
		}

		public static void RollAndFire(DeathContext ctx)
		{
			List<RouletteEvent> list = Table.Where((RouletteEvent e) => e.Weight > 0).ToList();
			if (_lastFiredId != null && list.Count > 1)
			{
				list.RemoveAll((RouletteEvent e) => e.Id == _lastFiredId);
			}
			while (list.Count > 0)
			{
				RouletteEvent rouletteEvent = WeightedPick(list);
				if (rouletteEvent == null)
				{
					break;
				}
				if (FireAndAnnounce(rouletteEvent, ctx))
				{
					return;
				}
				list.Remove(rouletteEvent);
			}
			Plugin.Log.LogWarning((object)"No event could fire.");
		}

		public static bool FireAndAnnounce(RouletteEvent ev, DeathContext ctx)
		{
			string text;
			try
			{
				text = ev.Fire(ctx);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Event '{ev.Id}' threw: {arg}");
				return false;
			}
			if (text == null)
			{
				if (Plugin.VerboseLogging.Value)
				{
					Plugin.Log.LogInfo((object)("Event '" + ev.Id + "' declined."));
				}
				return false;
			}
			Plugin.Log.LogInfo((object)(ctx.PlayerName + " died -> '" + ev.Id + "': " + text));
			_lastFiredId = ev.Id;
			Announce.Effect(ctx, ev, text);
			return true;
		}

		private static RouletteEvent WeightedPick(List<RouletteEvent> pool)
		{
			int num = pool.Sum((RouletteEvent e) => Math.Max(0, e.Weight));
			if (num <= 0)
			{
				return null;
			}
			int num2 = Rng.Next(num);
			foreach (RouletteEvent item in pool)
			{
				num2 -= Math.Max(0, item.Weight);
				if (num2 < 0)
				{
					return item;
				}
			}
			return pool[pool.Count - 1];
		}

		private static List<PlayerInfo> Survivors(DeathContext ctx)
		{
			List<PlayerInfo> list = ServerActions.OnlinePlayers();
			if (ctx.IsTest)
			{
				return list;
			}
			return list.Where((PlayerInfo p) => p.m_characterID != ctx.CharacterId).ToList();
		}

		private static Vector3 RandomHorizontal()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			float num = (float)(Rng.NextDouble() * Math.PI * 2.0);
			return new Vector3(Mathf.Cos(num), 0f, Mathf.Sin(num));
		}

		public static void DumpWorldData()
		{
			if (_dumped)
			{
				return;
			}
			_dumped = true;
			RandEventSystem res = RandEventSystem.instance;
			if (res?.m_events != null)
			{
				Plugin.Log.LogInfo((object)("Random events in this world: " + string.Join(", ", res.m_events.Select((RandomEvent e) => e.m_name + (e.m_enabled ? "" : " (disabled)")))));
				List<string> list = RaidPool.Where((string n) => !res.HaveEvent(n)).ToList();
				if (list.Count > 0)
				{
					Plugin.Log.LogWarning((object)("Raid pool names not available here (will be skipped): " + string.Join(", ", list)));
				}
			}
			else
			{
				Plugin.Log.LogWarning((object)"RandEventSystem not available; raid names unverified.");
			}
			int num = Table.Count((RouletteEvent e) => e.Weight > 0);
			Plugin.Log.LogInfo((object)$"{num}/{Table.Count} events enabled.");
		}

		public static void EnsureDumped()
		{
			if (!_dumped)
			{
				DumpWorldData();
			}
		}
	}
	internal static class ServerActions
	{
		internal enum Element
		{
			Fire,
			Frost,
			Poison,
			Lightning,
			Spirit
		}

		private static MethodInfo _getPossible;

		public static void ShowMessage(MessageType type, string text)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Expected I4, but got Unknown
			if (!string.IsNullOrEmpty(text))
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, "ShowMessage", new object[2]
				{
					(int)type,
					text
				});
			}
		}

		public static void ShowMessageTo(long peerId, MessageType type, string text)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected I4, but got Unknown
			if (!string.IsNullOrEmpty(text) && peerId != 0L)
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(peerId, "ShowMessage", new object[2]
				{
					(int)type,
					text
				});
			}
		}

		public static void PlayEffect(string prefabName, Vector3 pos)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, "SpawnObject", new object[3]
			{
				pos,
				Quaternion.identity,
				StringExtensionMethods.GetStableHashCode(prefabName)
			});
		}

		public static void PlayEffectAtEveryone(string prefabName)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			foreach (PlayerInfo item in OnlinePlayers())
			{
				PlayEffect(prefabName, PositionOf(item));
			}
		}

		public static bool SpawnNetworked(string prefabName, Vector3 pos)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			long num = AnyReadyPeer();
			if (num == 0L)
			{
				return false;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(num, "SpawnObject", new object[3]
			{
				pos,
				Quaternion.identity,
				StringExtensionMethods.GetStableHashCode(prefabName)
			});
			return true;
		}

		public static void AddStatusEffect(ZDOID target, string statusEffectName, bool resetTime = true)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, target, "RPC_AddStatusEffect", new object[5]
			{
				StringExtensionMethods.GetStableHashCode(statusEffectName),
				resetTime,
				0,
				0f,
				-1
			});
		}

		public static void AddStatusEffectToAll(string statusEffectName)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			foreach (PlayerInfo item in OnlinePlayers())
			{
				AddStatusEffect(item.m_characterID, statusEffectName);
			}
		}

		public static void Heal(ZDOID target, float hp, bool showText = true)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, target, "RPC_Heal", new object[2] { hp, showText });
		}

		public static void DamageCapped(ZDOID target, float amount, float maxFractionOfHealth = 0.25f)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			ZDOMan instance = ZDOMan.instance;
			ZDO val = ((instance != null) ? instance.GetZDO(target) : null);
			if (val == null)
			{
				return;
			}
			float num = val.GetFloat(ZDOVars.s_health, 0f);
			if (!(num <= 1f))
			{
				float num2 = Mathf.Min(amount, num * maxFractionOfHealth);
				if (!(num2 <= 0f))
				{
					HitData val2 = new HitData(num2)
					{
						m_point = val.GetPosition()
					};
					ZRoutedRpc.instance.InvokeRoutedRPC(0L, target, "RPC_Damage", new object[1] { val2 });
				}
			}
		}

		public static void DamageElemental(ZDOID target, Element element, float amount, float maxFraction = 0.25f)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			ZDOMan instance = ZDOMan.instance;
			ZDO val = ((instance != null) ? instance.GetZDO(target) : null);
			if (val == null)
			{
				return;
			}
			float num = val.GetFloat(ZDOVars.s_health, 0f);
			if (num <= 1f)
			{
				return;
			}
			float num2 = Mathf.Min(amount, num * maxFraction);
			if (!(num2 <= 0f))
			{
				HitData val2 = new HitData
				{
					m_point = val.GetPosition()
				};
				switch (element)
				{
				case Element.Fire:
					val2.m_damage.m_fire = num2;
					break;
				case Element.Frost:
					val2.m_damage.m_frost = num2;
					break;
				case Element.Poison:
					val2.m_damage.m_poison = num2;
					break;
				case Element.Spirit:
					val2.m_damage.m_spirit = num2;
					break;
				default:
					val2.m_damage.m_lightning = num2;
					break;
				}
				ZRoutedRpc.instance.InvokeRoutedRPC(0L, target, "RPC_Damage", new object[1] { val2 });
			}
		}

		public static void AddAdrenaline(ZDOID target, float amount)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, target, "RPC_AddAdrenaline", new object[1] { amount });
		}

		public static bool FindLocation(string locationName, Vector3 near, out Vector3 pos)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			pos = Vector3.zero;
			ZoneSystem instance = ZoneSystem.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			LocationInstance val = default(LocationInstance);
			if (!instance.FindClosestLocation(locationName, near, ref val))
			{
				return false;
			}
			pos = val.m_position;
			return true;
		}

		public static void Stagger(ZDOID target, Vector3 forceDirection)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, target, "RPC_Stagger", new object[1] { forceDirection });
		}

		public static void FreezeFrame(ZDOID target, float duration)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, target, "RPC_FreezeFrame", new object[1] { duration });
		}

		public static void AddNoise(ZDOID target, float range)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, target, "RPC_AddNoise", new object[1] { range });
		}

		public static void TeleportTo(ZDOID target, Vector3 pos, bool distantTeleport = true)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, target, "RPC_TeleportTo", new object[3]
			{
				pos,
				Quaternion.identity,
				distantTeleport
			});
		}

		public static void FloatingText(Vector3 pos, string text, TextType type = (TextType)7)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected I4, but got Unknown
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			ZPackage val = new ZPackage();
			val.Write((int)type);
			val.Write(pos);
			val.Write(text);
			val.Write(false);
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, "RPC_DamageText", new object[1] { val });
		}

		public static bool RevealLocation(long peerId, string locationName, Vector3 near, string pinName, PinType pinType)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected I4, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			ZoneSystem instance = ZoneSystem.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			LocationInstance val = default(LocationInstance);
			if (!instance.FindClosestLocation(locationName, near, ref val))
			{
				return false;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(peerId, "RPC_DiscoverLocationResponse", new object[4]
			{
				pinName,
				(int)pinType,
				val.m_position,
				false
			});
			return true;
		}

		public static long OwnerOf(ZDOID characterId)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			ZDOMan instance = ZDOMan.instance;
			ZDO obj = ((instance != null) ? instance.GetZDO(characterId) : null);
			if (obj == null)
			{
				return 0L;
			}
			return obj.GetOwner();
		}

		public static bool StartEvent(string eventName, Vector3 pos)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			RandEventSystem instance = RandEventSystem.instance;
			if ((Object)(object)instance == (Object)null || !instance.HaveEvent(eventName))
			{
				return false;
			}
			instance.SetRandomEventByName(eventName, pos);
			return true;
		}

		public static List<KeyValuePair<RandomEvent, Vector3>> PossibleRaids()
		{
			List<KeyValuePair<RandomEvent, Vector3>> list = new List<KeyValuePair<RandomEvent, Vector3>>();
			RandEventSystem instance = RandEventSystem.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return list;
			}
			if (_getPossible == null)
			{
				_getPossible = AccessTools.Method(typeof(RandEventSystem), "GetPossibleRandomEvents", (Type[])null, (Type[])null);
				if (_getPossible == null)
				{
					Plugin.Log.LogError((object)"RandEventSystem.GetPossibleRandomEvents not found; raids cannot be gated.");
					return list;
				}
			}
			try
			{
				return (!(_getPossible.Invoke(instance, null) is List<KeyValuePair<RandomEvent, Vector3>> collection)) ? list : new List<KeyValuePair<RandomEvent, Vector3>>(collection);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("GetPossibleRandomEvents failed: " + ex.Message));
				return list;
			}
		}

		public static bool SkipToMorning()
		{
			EnvMan instance = EnvMan.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			instance.SkipToMorning();
			return true;
		}

		public static bool HaveActiveRaid()
		{
			if ((Object)(object)RandEventSystem.instance != (Object)null)
			{
				return RandEventSystem.HaveActiveEvent();
			}
			return false;
		}

		public static bool StopEvent()
		{
			RandEventSystem instance = RandEventSystem.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			instance.ResetRandomEvent();
			return true;
		}

		public static bool HasGlobalKey(string key)
		{
			if ((Object)(object)ZoneSystem.instance != (Object)null)
			{
				return ZoneSystem.instance.GetGlobalKey(key);
			}
			return false;
		}

		public static void SetGlobalKey(string key)
		{
			ZoneSystem instance = ZoneSystem.instance;
			if (instance != null)
			{
				instance.SetGlobalKey(key);
			}
		}

		public static List<PlayerInfo> OnlinePlayers()
		{
			ZNet instance = ZNet.instance;
			return ((instance != null) ? instance.GetPlayerList() : null) ?? new List<PlayerInfo>();
		}

		public static bool IsAdmin(long peerId)
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null || peerId == 0L)
			{
				return false;
			}
			ZNetPeer peer = instance.GetPeer(peerId);
			object obj;
			if (peer == null)
			{
				obj = null;
			}
			else
			{
				ISocket socket = peer.m_socket;
				obj = ((socket != null) ? socket.GetHostName() : null);
			}
			string text = (string)obj;
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			return instance.IsAdmin(text);
		}

		public static Vector3 PositionOf(ZDOID characterId, Vector3 fallback)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			ZDOMan instance = ZDOMan.instance;
			ZDO obj = ((instance != null) ? instance.GetZDO(characterId) : null);
			if (obj == null)
			{
				return fallback;
			}
			return obj.GetPosition();
		}

		public static Vector3 PositionOf(PlayerInfo p)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			return PositionOf(p.m_characterID, p.m_position);
		}

		private static long AnyReadyPeer()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			foreach (PlayerInfo item in OnlinePlayers())
			{
				ZDOMan instance = ZDOMan.instance;
				ZDO obj = ((instance != null) ? instance.GetZDO(item.m_characterID) : null);
				long num = ((obj != null) ? obj.GetOwner() : 0);
				if (num != 0L)
				{
					return num;
				}
			}
			return 0L;
		}
	}
	[HarmonyPatch(typeof(ZoneSystem), "Start")]
	internal static class StartupPatch
	{
		[HarmonyPostfix]
		private static void Postfix()
		{
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				RouletteEvents.DumpWorldData();
			}
		}
	}
}