Decompiled source of HexedRisk v1.0.1

plugins/HexedRisk/HexedRisk.dll

Decompiled 5 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Microsoft.CodeAnalysis;
using On.RoR2;
using R2API;
using R2API.Networking;
using R2API.Networking.Interfaces;
using RoR2;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 HexedRisk
{
	internal enum HexId : byte
	{
		GlassCannon,
		GetExcited,
		Minionmancer,
		Earthwake,
		Dropkick,
		TapDancer,
		DoubleTap,
		MagicMissile,
		InfernalConduit,
		CircleOfDeath,
		ShowYourSword,
		ShrinkEngine,
		ToothFairy,
		Goliath,
		NearDeathInsight,
		TankEngine,
		EtherealWeapon,
		Vulnerability,
		BackToBasics,
		GiantSlayer,
		Firebrand,
		PandorasBox,
		MysticPunch,
		Archmage,
		TransmuteChaos,
		TransmutePrismatic,
		TransmuteGold
	}
	internal sealed class HexDefinition
	{
		internal HexId Id { get; }

		internal string Name { get; }

		internal string Description { get; }

		internal string Accent { get; }

		internal HexDefinition(HexId id, string name, string description, string accent)
		{
			Id = id;
			Name = name;
			Description = description;
			Accent = accent;
		}
	}
	internal static class HexCatalog
	{
		internal static readonly IReadOnlyList<HexDefinition> All = new HexDefinition[27]
		{
			new HexDefinition(HexId.GlassCannon, "玻璃大炮", "最大生命值降低 30%,所有伤害提高 25%", "#e879f9"),
			new HexDefinition(HexId.GetExcited, "罪恶快感", "击杀后获得 40% 移速和 20% 攻速,持续 4 秒;击杀精英持续 8 秒", "#facc15"),
			new HexDefinition(HexId.Minionmancer, "仆从大师", "无人机、炮塔和召唤物获得 40% 生命与伤害,体型增大 150%", "#facc15"),
			new HexDefinition(HexId.Earthwake, "大地苏醒", "使用位移技能后在原地留下震点,1 秒后爆炸,造成 300% 基础伤害", "#e879f9"),
			new HexDefinition(HexId.Dropkick, "飞身踢", "处决阈值为 10% 加最大生命值成长:每 200 最大生命值提高 1%;Boss 不会被处决", "#e879f9"),
			new HexDefinition(HexId.TapDancer, "踢踏舞", "普攻获得 1 米/秒移速,持续 4 秒;额外移速的 75% 转为攻速,第一关最多 20 层,此后每关上限增加 10 层", "#e879f9"),
			new HexDefinition(HexId.DoubleTap, "双发快射", "暴击会额外触发一次攻击特效,不会递归触发自身", "#facc15"),
			new HexDefinition(HexId.MagicMissile, "魔法飞弹", "技能命中发射 3 枚追踪弹;每枚造成目标最大生命值 1% 的伤害,Boss 有伤害上限", "#facc15"),
			new HexDefinition(HexId.InfernalConduit, "炼狱导管", "技能命中施加灼烧;灼烧伤害每 0.25 秒最多缩短全部技能冷却 0.2 秒", "#e879f9"),
			new HexDefinition(HexId.CircleOfDeath, "死亡之环", "获得治疗时对最近敌人造成治疗量 150% 的伤害,每秒最多触发 4 次", "#e879f9"),
			new HexDefinition(HexId.ShowYourSword, "亮出你的剑", "攻击距离限制为 15 米;获得 24% 伤害与生命、20% 攻速与移速及 5% 吸血", "#e879f9"),
			new HexDefinition(HexId.ShrinkEngine, "缩小引擎", "击杀精英后体型缩小 5%,获得 5% 冷却缩减和 5% 移速;冷却缩减上限 80%,死亡损失 65% 层数", "#facc15"),
			new HexDefinition(HexId.ToothFairy, "牙仙子", "4 秒内对同一目标造成其 25% 最大生命伤害时自动吸收牙齿;每层增加 10% 无视护甲几率,本关最多 10 层", "#facc15"),
			new HexDefinition(HexId.Goliath, "歌利亚巨人", "体型增大 50%,最大生命值提高 50%,伤害提高 25%,移动速度降低 10%", "#e879f9"),
			new HexDefinition(HexId.NearDeathInsight, "濒死悟道", "受到致命伤时免疫该次伤害并恢复至 35% 生命,冷却 240 秒", "#e879f9"),
			new HexDefinition(HexId.TankEngine, "坦克引擎", "击杀精英或 Boss 获得 1 层:体型和最大生命值各提高 10%;死亡损失 65% 层数", "#facc15"),
			new HexDefinition(HexId.EtherealWeapon, "虚幻武器", "伤害技能额外触发一次攻击特效,同一目标冷却 0.5 秒", "#facc15"),
			new HexDefinition(HexId.Vulnerability, "易损", "获得 25% 暴击率;主动装备伤害和持续伤害可以暴击", "#facc15"),
			new HexDefinition(HexId.BackToBasics, "回归基本功", "封印特殊技能;其他三类技能伤害和治疗提高 50%,冷却缩短 40%", "#e879f9"),
			new HexDefinition(HexId.GiantSlayer, "巨人杀手", "体型缩小 25% 并获得 20% 移速;对更大敌人造成 10%-30% 额外伤害", "#e879f9"),
			new HexDefinition(HexId.Firebrand, "火上浇油", "攻击施加持续 5 秒的灼烧,每次攻击累计目标最大生命值 0.5% 的总伤害", "#facc15"),
			new HexDefinition(HexId.PandorasBox, "潘朵拉的盒子", "消耗自身,将当前全部海克斯随机重铸为不重复的棱彩海克斯", "#e879f9"),
			new HexDefinition(HexId.MysticPunch, "秘术冲拳", "攻击特效命中时使全部技能冷却缩短 0.25 秒,每秒最多 4 次", "#e879f9"),
			new HexDefinition(HexId.Archmage, "大法师", "施放技能时,随机使另一个技能返还本次技能基础冷却的 30%", "#e879f9"),
			new HexDefinition(HexId.TransmuteChaos, "质变:混沌", "消耗自身,按等级权重随机获得 2 个不重复海克斯", "#e879f9"),
			new HexDefinition(HexId.TransmutePrismatic, "质变:棱彩阶", "消耗自身,随机获得 1 个未拥有的棱彩海克斯", "#facc15"),
			new HexDefinition(HexId.TransmuteGold, "质变:黄金阶", "消耗自身,随机获得 1 个未拥有的黄金海克斯", "#c0c0c0")
		};

		internal static readonly HexId[] PrismaticPool = new HexId[13]
		{
			HexId.GlassCannon,
			HexId.Earthwake,
			HexId.Dropkick,
			HexId.TapDancer,
			HexId.InfernalConduit,
			HexId.CircleOfDeath,
			HexId.ShowYourSword,
			HexId.Goliath,
			HexId.NearDeathInsight,
			HexId.BackToBasics,
			HexId.GiantSlayer,
			HexId.MysticPunch,
			HexId.Archmage
		};

		internal static readonly HexId[] GoldPool = new HexId[10]
		{
			HexId.GetExcited,
			HexId.Minionmancer,
			HexId.DoubleTap,
			HexId.MagicMissile,
			HexId.ShrinkEngine,
			HexId.ToothFairy,
			HexId.TankEngine,
			HexId.EtherealWeapon,
			HexId.Vulnerability,
			HexId.Firebrand
		};

		private static readonly Dictionary<HexId, HexDefinition> ById = BuildIndex();

		internal static HexDefinition Get(HexId id)
		{
			return ById[id];
		}

		internal static bool HasAvailable(CharacterMaster master)
		{
			return All.Any((HexDefinition hex) => HexRunState.GetStacks(master, hex.Id) == 0);
		}

		internal static HexDefinition[] RollThree(CharacterMaster master, Random random)
		{
			HexDefinition[] array = All.Where((HexDefinition hex) => HexRunState.GetStacks(master, hex.Id) == 0).ToArray();
			int[] array2 = new int[array.Length];
			for (int num = 0; num < array.Length; num++)
			{
				array2[num] = num;
			}
			int num2 = Math.Min(3, array2.Length);
			for (int num3 = 0; num3 < num2; num3++)
			{
				int num4 = random.Next(num3, array2.Length);
				ref int reference = ref array2[num3];
				ref int reference2 = ref array2[num4];
				int num5 = array2[num4];
				int num6 = array2[num3];
				reference = num5;
				reference2 = num6;
			}
			HexDefinition[] array3 = new HexDefinition[num2];
			for (int num7 = 0; num7 < num2; num7++)
			{
				array3[num7] = array[array2[num7]];
			}
			return array3;
		}

		private static Dictionary<HexId, HexDefinition> BuildIndex()
		{
			Dictionary<HexId, HexDefinition> dictionary = new Dictionary<HexId, HexDefinition>();
			foreach (HexDefinition item in All)
			{
				dictionary.Add(item.Id, item);
			}
			return dictionary;
		}
	}
	internal sealed class HexPickerUI
	{
		private readonly Action<CharacterMaster, HexId> _onSelected;

		private readonly ConfigEntry<bool> _showOverlay;

		private readonly Random _random = new Random();

		private HexDefinition[] _choices = Array.Empty<HexDefinition>();

		private CharacterMaster? _owner;

		private int _rerollsLeft;

		private bool _visible;

		private bool _overlayVisible = true;

		private CursorLockMode _previousLockMode;

		private bool _previousCursorVisible;

		private Font? _font;

		private GUIStyle? _titleStyle;

		private GUIStyle? _subtitleStyle;

		private GUIStyle? _cardStyle;

		private GUIStyle? _buttonStyle;

		private GUIStyle? _overlayStyle;

		internal bool IsVisible => _visible;

		internal HexPickerUI(Action<CharacterMaster, HexId> onSelected, ConfigEntry<bool> showOverlay)
		{
			_onSelected = onSelected;
			_showOverlay = showOverlay;
		}

		internal void Open(CharacterMaster owner, int rerolls)
		{
			//IL_0030: 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)
			if (!_visible)
			{
				_owner = owner;
				_rerollsLeft = Math.Max(0, rerolls);
				_choices = HexCatalog.RollThree(owner, _random);
				_previousLockMode = Cursor.lockState;
				_previousCursorVisible = Cursor.visible;
				_visible = true;
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
		}

		internal void Close()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			if (_visible)
			{
				_visible = false;
				_owner = null;
				Cursor.lockState = _previousLockMode;
				Cursor.visible = _previousCursorVisible;
			}
		}

		internal void Update()
		{
			if (Input.GetKeyDown((KeyCode)288))
			{
				_overlayVisible = !_overlayVisible;
			}
			if (_visible)
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
		}

		internal void Draw()
		{
			//IL_002a: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_029c: Unknown result type (might be due to invalid IL or missing references)
			EnsureStyles();
			if (_showOverlay.Value && _overlayVisible)
			{
				DrawActiveHexes();
			}
			if (!_visible)
			{
				return;
			}
			Color color = GUI.color;
			GUI.color = new Color(0f, 0f, 0f, 0.72f);
			GUI.DrawTexture(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height), (Texture)(object)Texture2D.whiteTexture);
			GUI.color = color;
			float num = Mathf.Min(1120f, (float)Screen.width - 60f);
			float num2 = Mathf.Min(590f, (float)Screen.height - 60f);
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(((float)Screen.width - num) / 2f, ((float)Screen.height - num2) / 2f, num, num2);
			GUI.Box(val, GUIContent.none, _overlayStyle);
			GUI.Label(new Rect(((Rect)(ref val)).x + 30f, ((Rect)(ref val)).y + 22f, ((Rect)(ref val)).width - 60f, 48f), "选择一个海克斯", _titleStyle);
			GUI.Label(new Rect(((Rect)(ref val)).x + 30f, ((Rect)(ref val)).y + 69f, ((Rect)(ref val)).width - 60f, 30f), "仅对你的角色生效,并持续至本局结束", _subtitleStyle);
			float num3 = 18f;
			float num4 = (((Rect)(ref val)).width - 60f - num3 * 2f) / 3f;
			for (int i = 0; i < _choices.Length; i++)
			{
				HexDefinition hexDefinition = _choices[i];
				string text = "<size=26><color=" + hexDefinition.Accent + ">" + hexDefinition.Name + "</color></size>\n\n<size=18>" + hexDefinition.Description + "</size>";
				if (GUI.Button(new Rect(((Rect)(ref val)).x + 30f + (float)i * (num4 + num3), ((Rect)(ref val)).y + 118f, num4, ((Rect)(ref val)).height - 205f), text, _cardStyle))
				{
					if ((Object)(object)_owner != (Object)null)
					{
						_onSelected(_owner, hexDefinition.Id);
					}
					Close();
				}
			}
			GUI.enabled = _rerollsLeft > 0;
			if (GUI.Button(new Rect(((Rect)(ref val)).center.x - 145f, ((Rect)(ref val)).yMax - 68f, 290f, 44f), $"刷新选项(剩余 {_rerollsLeft} 次)", _buttonStyle))
			{
				_rerollsLeft--;
				if ((Object)(object)_owner != (Object)null)
				{
					_choices = HexCatalog.RollThree(_owner, _random);
				}
			}
			GUI.enabled = true;
		}

		private void DrawActiveHexes()
		{
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			string text = "<b>海克斯</b>  <size=13>[F7 隐藏]</size>";
			int num = 0;
			LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
			CharacterMaster val = ((firstLocalUser != null) ? firstLocalUser.cachedMaster : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			foreach (KeyValuePair<HexId, int> item in HexRunState.Enumerate(val))
			{
				HexDefinition hexDefinition = HexCatalog.Get(item.Key);
				text += $"\n<color={hexDefinition.Accent}>{hexDefinition.Name}</color> ×{item.Value}";
				num++;
			}
			if (num != 0)
			{
				float num2 = 42f + (float)num * 24f;
				GUI.Box(new Rect(18f, 90f, 245f, num2), text, _overlayStyle);
			}
		}

		private void EnsureStyles()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_0066: 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_007b: Expected O, but got Unknown
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Expected O, but got Unknown
			//IL_011b: Expected O, but got Unknown
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Expected O, but got Unknown
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Expected O, but got Unknown
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Expected O, but got Unknown
			if (_titleStyle == null)
			{
				_font = Font.CreateDynamicFontFromOSFont(new string[3] { "Microsoft YaHei UI", "Microsoft YaHei", "Arial" }, 22);
				GUIStyle val = new GUIStyle(GUI.skin.label)
				{
					font = _font,
					fontSize = 34,
					alignment = (TextAnchor)4,
					fontStyle = (FontStyle)1
				};
				val.normal.textColor = Color.white;
				_titleStyle = val;
				GUIStyle val2 = new GUIStyle(GUI.skin.label)
				{
					font = _font,
					fontSize = 17,
					alignment = (TextAnchor)4
				};
				val2.normal.textColor = new Color(0.78f, 0.82f, 0.88f);
				_subtitleStyle = val2;
				_cardStyle = new GUIStyle(GUI.skin.button)
				{
					font = _font,
					fontSize = 18,
					alignment = (TextAnchor)4,
					wordWrap = true,
					richText = true,
					padding = new RectOffset(20, 20, 20, 20)
				};
				_buttonStyle = new GUIStyle(GUI.skin.button)
				{
					font = _font,
					fontSize = 17,
					alignment = (TextAnchor)4
				};
				GUIStyle val3 = new GUIStyle(GUI.skin.box)
				{
					font = _font,
					fontSize = 16,
					alignment = (TextAnchor)0,
					richText = true,
					padding = new RectOffset(14, 14, 12, 12)
				};
				val3.normal.textColor = Color.white;
				_overlayStyle = val3;
			}
		}
	}
	internal static class HexRunState
	{
		private static readonly Dictionary<CharacterMaster, Dictionary<HexId, int>> PlayerStacks = new Dictionary<CharacterMaster, Dictionary<HexId, int>>();

		private static readonly Dictionary<CharacterBody, float> ExcitedUntil = new Dictionary<CharacterBody, float>();

		private static readonly Dictionary<CharacterBody, TimedStackState> TapDancerStates = new Dictionary<CharacterBody, TimedStackState>();

		private static readonly Dictionary<CharacterBody, float> InfernalNextRecharge = new Dictionary<CharacterBody, float>();

		private static readonly Dictionary<CharacterBody, TriggerWindow> CircleTriggerWindows = new Dictionary<CharacterBody, TriggerWindow>();

		private static readonly Dictionary<CharacterMaster, int> ShrinkEngineStacks = new Dictionary<CharacterMaster, int>();

		private static readonly Dictionary<CharacterMaster, int> TankEngineStacks = new Dictionary<CharacterMaster, int>();

		private static readonly Dictionary<CharacterMaster, int> ToothStacks = new Dictionary<CharacterMaster, int>();

		private static readonly Dictionary<(CharacterMaster, HealthComponent), ToothProgress> ToothProgresses = new Dictionary<(CharacterMaster, HealthComponent), ToothProgress>();

		private static readonly Dictionary<CharacterMaster, float> NearDeathReadyAt = new Dictionary<CharacterMaster, float>();

		private static readonly Dictionary<(CharacterBody, HealthComponent), float> EtherealReadyAt = new Dictionary<(CharacterBody, HealthComponent), float>();

		private static readonly Dictionary<CharacterBody, TriggerWindow> MysticPunchWindows = new Dictionary<CharacterBody, TriggerWindow>();

		private static readonly HashSet<HealthComponent> DropkickExecuting = new HashSet<HealthComponent>();

		private static GameObject? _missileProjectilePrefab;

		internal static event Action? Changed;

		internal static int GetStacks(CharacterMaster? master, HexId id)
		{
			if (!((Object)(object)master != (Object)null) || !PlayerStacks.TryGetValue(master, out Dictionary<HexId, int> value) || !value.TryGetValue(id, out var value2))
			{
				return 0;
			}
			return value2;
		}

		internal static IEnumerable<KeyValuePair<HexId, int>> Enumerate(CharacterMaster master)
		{
			if (!PlayerStacks.TryGetValue(master, out Dictionary<HexId, int> value))
			{
				return Array.Empty<KeyValuePair<HexId, int>>();
			}
			return value;
		}

		internal static IEnumerable<KeyValuePair<CharacterMaster, IEnumerable<KeyValuePair<HexId, int>>>> EnumeratePlayers()
		{
			foreach (KeyValuePair<CharacterMaster, Dictionary<HexId, int>> playerStack in PlayerStacks)
			{
				if ((Object)(object)playerStack.Key != (Object)null)
				{
					yield return new KeyValuePair<CharacterMaster, IEnumerable<KeyValuePair<HexId, int>>>(playerStack.Key, playerStack.Value);
				}
			}
		}

		internal static void Reset()
		{
			ClearRuntimeEffects();
			PlayerStacks.Clear();
			HexRunState.Changed?.Invoke();
			RefreshAllBodies();
		}

		internal static void Add(CharacterMaster master, HexId id)
		{
			Dictionary<HexId, int> orCreateStacks = GetOrCreateStacks(master);
			switch (id)
			{
			case HexId.PandorasBox:
			{
				int count = orCreateStacks.Count;
				orCreateStacks.Clear();
				AddRandomUnique(orCreateStacks, HexCatalog.PrismaticPool, count);
				break;
			}
			case HexId.TransmuteChaos:
				AddChaosReward(orCreateStacks);
				AddChaosReward(orCreateStacks);
				break;
			case HexId.TransmutePrismatic:
				AddRandomUnique(orCreateStacks, HexCatalog.PrismaticPool, 1);
				break;
			case HexId.TransmuteGold:
				AddRandomUnique(orCreateStacks, HexCatalog.GoldPool, 1);
				break;
			default:
				orCreateStacks[id] = 1;
				break;
			}
			HexRunState.Changed?.Invoke();
			RefreshAllBodies();
		}

		private static void AddChaosReward(Dictionary<HexId, int> stacks)
		{
			int num = Random.Range(0, 100);
			AddRandomUnique(stacks, (num >= 80) ? HexCatalog.PrismaticPool : HexCatalog.GoldPool, 1);
		}

		private static void AddRandomUnique(Dictionary<HexId, int> stacks, IReadOnlyList<HexId> pool, int count)
		{
			List<HexId> list = new List<HexId>();
			foreach (HexId item in pool)
			{
				if (!stacks.ContainsKey(item))
				{
					list.Add(item);
				}
			}
			while (count-- > 0 && list.Count > 0)
			{
				int index = Random.Range(0, list.Count);
				stacks[list[index]] = 1;
				list.RemoveAt(index);
			}
		}

		internal static void Replace(CharacterMaster master, IEnumerable<KeyValuePair<HexId, int>> values)
		{
			Dictionary<HexId, int> orCreateStacks = GetOrCreateStacks(master);
			orCreateStacks.Clear();
			foreach (KeyValuePair<HexId, int> value in values)
			{
				if (value.Value > 0 && Enum.IsDefined(typeof(HexId), value.Key))
				{
					orCreateStacks[value.Key] = 1;
				}
			}
			HexRunState.Changed?.Invoke();
			RefreshAllBodies();
		}

		private static Dictionary<HexId, int> GetOrCreateStacks(CharacterMaster master)
		{
			if (!PlayerStacks.TryGetValue(master, out Dictionary<HexId, int> value))
			{
				value = new Dictionary<HexId, int>();
				PlayerStacks[master] = value;
			}
			return value;
		}

		internal static void ApplyStats(CharacterBody body, StatHookEventArgs args)
		{
			if ((Object)(object)body == (Object)null)
			{
				return;
			}
			CharacterMaster master = body.master;
			if (IsPlayerBody(body))
			{
				if (GetStacks(master, HexId.GlassCannon) > 0)
				{
					args.healthMultAdd -= 0.3f;
					args.damageMultAdd += 0.25f;
				}
				if (ExcitedUntil.TryGetValue(body, out var value) && value > Time.fixedTime)
				{
					args.moveSpeedMultAdd += 0.4f;
					args.attackSpeedMultAdd += 0.2f;
				}
				if (TapDancerStates.TryGetValue(body, out var value2) && value2.EndTime > Time.fixedTime)
				{
					float num = 1f * (float)value2.Stacks;
					args.baseMoveSpeedAdd += num;
					float num2 = Mathf.Max(body.moveSpeed, body.baseMoveSpeed + num);
					args.attackSpeedMultAdd += Mathf.Max(0f, num2 / Mathf.Max(1f, body.baseMoveSpeed) - 1f) * 0.75f;
				}
				if (GetStacks(master, HexId.ShowYourSword) > 0)
				{
					args.healthMultAdd += 0.24f;
					args.damageMultAdd += 0.24f;
					args.attackSpeedMultAdd += 0.2f;
					args.moveSpeedMultAdd += 0.2f;
				}
				if ((Object)(object)master != (Object)null && ShrinkEngineStacks.TryGetValue(master, out var value3))
				{
					args.allSkills.cooldownMultAdd -= Mathf.Min(0.8f, (float)value3 * 0.05f);
					args.moveSpeedMultAdd += (float)value3 * 0.05f;
				}
				if (GetStacks(master, HexId.Goliath) > 0)
				{
					args.healthMultAdd += 0.5f;
					args.damageMultAdd += 0.25f;
					args.moveSpeedMultAdd -= 0.1f;
				}
				if ((Object)(object)master != (Object)null && TankEngineStacks.TryGetValue(master, out var value4))
				{
					args.healthMultAdd += (float)value4 * 0.1f;
				}
				if (GetStacks(master, HexId.Vulnerability) > 0)
				{
					args.critAdd += 25f;
				}
				if (GetStacks(master, HexId.BackToBasics) > 0)
				{
					args.primarySkill.cooldownMultAdd -= 0.4f;
					args.secondarySkill.cooldownMultAdd -= 0.4f;
					args.utilitySkill.cooldownMultAdd -= 0.4f;
				}
				if (GetStacks(master, HexId.GiantSlayer) > 0)
				{
					args.moveSpeedMultAdd += 0.2f;
				}
			}
			CharacterMaster master2 = body.master;
			object master3;
			if (master2 == null)
			{
				master3 = null;
			}
			else
			{
				MinionOwnership minionOwnership = master2.minionOwnership;
				master3 = ((minionOwnership != null) ? minionOwnership.ownerMaster : null);
			}
			if (GetStacks((CharacterMaster?)master3, HexId.Minionmancer) > 0 && IsPlayerMinion(body))
			{
				args.healthMultAdd += 0.4f;
				args.damageMultAdd += 0.4f;
			}
		}

		internal static void OnCharacterDeath(DamageReport report)
		{
			if (!NetworkServer.active)
			{
				return;
			}
			CharacterBody val = report.attackerBody;
			if (!IsPlayerBody(val))
			{
				CharacterMaster attackerOwnerMaster = report.attackerOwnerMaster;
				val = ((attackerOwnerMaster != null) ? attackerOwnerMaster.GetBody() : null);
			}
			if (IsPlayerBody(val))
			{
				if (GetStacks(val.master, HexId.GetExcited) > 0)
				{
					float duration = ((report.victimIsElite || report.victimIsBoss) ? 8f : 4f);
					ActivateGetExcited(val, duration);
					NetMessageExtensions.Send((INetMessage)(object)new GetExcitedMessage(((Component)val).gameObject, duration), (NetworkDestination)1);
				}
				if (GetStacks(val.master, HexId.ShrinkEngine) > 0 && report.victimIsElite && (Object)(object)val.master != (Object)null)
				{
					SetAndBroadcastShrinkStacks(val.master, GetShrinkStacks(val.master) + 1);
				}
				if (GetStacks(val.master, HexId.TankEngine) > 0 && (report.victimIsElite || report.victimIsBoss) && (Object)(object)val.master != (Object)null)
				{
					SetAndBroadcastTankStacks(val.master, GetTankStacks(val.master) + 1);
				}
			}
			CharacterMaster val2 = (IsPlayerBody(report.victimBody) ? report.victimBody.master : null);
			if (GetStacks(val2, HexId.ShrinkEngine) > 0 && (Object)(object)val2 != (Object)null)
			{
				SetAndBroadcastShrinkStacks(val2, Mathf.FloorToInt((float)GetShrinkStacks(val2) * 0.35f));
			}
			if (GetStacks(val2, HexId.TankEngine) > 0 && (Object)(object)val2 != (Object)null)
			{
				SetAndBroadcastTankStacks(val2, Mathf.FloorToInt((float)GetTankStacks(val2) * 0.35f));
			}
		}

		internal static bool OnSkillExecute(orig_ExecuteIfReady orig, GenericSkill self)
		{
			CharacterBody characterBody = self.characterBody;
			if (GetStacks((characterBody != null) ? characterBody.master : null, HexId.BackToBasics) > 0 && IsPlayerBody(characterBody) && (Object)(object)characterBody.skillLocator != (Object)null && (Object)(object)self == (Object)(object)characterBody.skillLocator.special)
			{
				return false;
			}
			bool flag = orig.Invoke(self);
			if (!flag || !NetworkServer.active)
			{
				return flag;
			}
			if (GetStacks((characterBody != null) ? characterBody.master : null, HexId.Earthwake) > 0 && IsPlayerBody(characterBody) && (Object)(object)characterBody.skillLocator != (Object)null && (Object)(object)self == (Object)(object)characterBody.skillLocator.utility)
			{
				Plugin.Instance.StartManagedCoroutine(DetonateEarthwake(characterBody));
			}
			if (GetStacks((characterBody != null) ? characterBody.master : null, HexId.Archmage) > 0 && IsPlayerBody(characterBody))
			{
				RechargeRandomOtherSkill(characterBody, self, self.baseRechargeInterval * 0.3f);
			}
			return flag;
		}

		internal static void OnServerDamageDealt(DamageReport report)
		{
			if (NetworkServer.active && !((Object)(object)report.attackerBody == (Object)null) && !((Object)(object)report.victim == (Object)null) && !((Object)(object)report.victimBody == (Object)null))
			{
				CharacterBody attackerBody = report.attackerBody;
				if (IsPlayerBody(attackerBody))
				{
					HandleTapDancer(report, attackerBody);
					HandleDoubleTap(report, attackerBody);
					HandleMagicMissile(report, attackerBody);
					HandleInfernalConduit(report, attackerBody);
					HandleDropkick(report, attackerBody);
					HandleShowYourSword(report, attackerBody);
					HandleToothFairy(report, attackerBody);
					HandleEtherealWeapon(report, attackerBody);
					HandleFirebrand(report, attackerBody);
					HandleMysticPunch(report, attackerBody);
				}
			}
		}

		private static void HandleTapDancer(DamageReport report, CharacterBody attacker)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			if (GetStacks(attacker.master, HexId.TapDancer) != 0 && (int)report.damageInfo.damageType.damageSource == 1)
			{
				TimedStackState value;
				int num = ((TapDancerStates.TryGetValue(attacker, out value) && value.EndTime > Time.fixedTime) ? value.Stacks : 0);
				int stacks = Mathf.Min(GetTapDancerStackLimit(), num + 1);
				ActivateTapDancer(attacker, stacks, 4f);
				NetMessageExtensions.Send((INetMessage)(object)new TapDancerMessage(((Component)attacker).gameObject, stacks, 4f), (NetworkDestination)1);
			}
		}

		private static void HandleDoubleTap(DamageReport report, CharacterBody attacker)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			ProcChainMask procChainMask = report.damageInfo.procChainMask;
			if (GetStacks(attacker.master, HexId.DoubleTap) != 0 && report.damageInfo.crit && !((ProcChainMask)(ref procChainMask)).HasProc((ProcType)15))
			{
				((ProcChainMask)(ref procChainMask)).AddProc((ProcType)15);
				DamageInfo damageInfo = report.damageInfo;
				damageInfo.procChainMask = procChainMask;
				GlobalEventManager.instance.OnHitEnemy(damageInfo, ((Component)report.victimBody).gameObject);
			}
		}

		private static void HandleMagicMissile(DamageReport report, CharacterBody attacker)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			ProcChainMask procChainMask = report.damageInfo.procChainMask;
			if (GetStacks(attacker.master, HexId.MagicMissile) == 0 || !IsNonPrimarySkillDamage(report.damageInfo) || ((ProcChainMask)(ref procChainMask)).HasProc((ProcType)1))
			{
				return;
			}
			if (_missileProjectilePrefab == null)
			{
				_missileProjectilePrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/MissileProjectile");
			}
			if (!((Object)(object)_missileProjectilePrefab == (Object)null))
			{
				((ProcChainMask)(ref procChainMask)).AddProc((ProcType)1);
				float num = report.victimBody.maxHealth * 0.01f;
				if (report.victimIsBoss)
				{
					num = Mathf.Min(num, attacker.damage * 3f);
				}
				for (int i = 0; i < 3; i++)
				{
					MissileUtils.FireMissile(attacker.corePosition, attacker, procChainMask, ((Component)report.victimBody).gameObject, num, Util.CheckRoll(attacker.crit, attacker.master), _missileProjectilePrefab, (DamageColorIndex)3, true);
				}
			}
		}

		private static void HandleInfernalConduit(DamageReport report, CharacterBody attacker)
		{
			//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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: 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)
			if (GetStacks(attacker.master, HexId.InfernalConduit) == 0)
			{
				return;
			}
			DotIndex dotIndex = report.damageInfo.dotIndex;
			if ((int)dotIndex == 1 || (int)dotIndex == 7)
			{
				if (!InfernalNextRecharge.TryGetValue(attacker, out var value) || value <= Time.fixedTime)
				{
					InfernalNextRecharge[attacker] = Time.fixedTime + 0.25f;
					RechargeAllSkills(attacker, 0.2f);
				}
			}
			else if (IsSkillDamage(report.damageInfo) && !((ProcChainMask)(ref report.damageInfo.procChainMask)).HasProc((ProcType)1))
			{
				InflictDotInfo val = new InflictDotInfo
				{
					victimObject = ((Component)report.victimBody).gameObject,
					attackerObject = ((Component)attacker).gameObject,
					dotIndex = (DotIndex)1,
					duration = 3f,
					damageMultiplier = 0.5f
				};
				DotController.InflictDot(ref val);
			}
		}

		private static void HandleDropkick(DamageReport report, CharacterBody attacker)
		{
			//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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			float num = 0.1f + Mathf.Floor(attacker.maxHealth / 200f) * 0.01f;
			if (GetStacks(attacker.master, HexId.Dropkick) == 0 || report.victimIsBoss || !report.victim.alive || report.victim.combinedHealthFraction > num || !DropkickExecuting.Add(report.victim))
			{
				return;
			}
			try
			{
				CharacterBody victimBody = report.victimBody;
				Vector3 corePosition = victimBody.corePosition;
				if ((Object)(object)victimBody.characterMotor != (Object)null)
				{
					Vector3 val = victimBody.corePosition - attacker.corePosition;
					Vector3 normalized = ((Vector3)(ref val)).normalized;
					victimBody.characterMotor.ApplyForce(normalized * 2800f + Vector3.up * 900f, true, false);
				}
				report.victim.Suicide(((Component)attacker).gameObject, ((Component)attacker).gameObject, DamageTypeCombo.op_Implicit((DamageType)0));
				FireBlast(attacker, corePosition, 2f, 8f, 0f);
			}
			finally
			{
				DropkickExecuting.Remove(report.victim);
			}
		}

		private static void HandleShowYourSword(DamageReport report, CharacterBody attacker)
		{
			//IL_0036: 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)
			if (GetStacks(attacker.master, HexId.ShowYourSword) > 0 && report.damageDealt > 0f)
			{
				HealthComponent healthComponent = attacker.healthComponent;
				if (healthComponent != null)
				{
					healthComponent.Heal(report.damageDealt * 0.05f, default(ProcChainMask), true);
				}
			}
		}

		private static void HandleToothFairy(DamageReport report, CharacterBody attacker)
		{
			if (GetStacks(attacker.master, HexId.ToothFairy) == 0 || (Object)(object)attacker.master == (Object)null || (Object)(object)report.victim == (Object)null || report.damageDealt <= 0f)
			{
				return;
			}
			(CharacterMaster, HealthComponent) key = (attacker.master, report.victim);
			float fixedTime = Time.fixedTime;
			ToothProgress value;
			ToothProgress toothProgress = ((ToothProgresses.TryGetValue(key, out value) && value.EndTime > fixedTime) ? value : new ToothProgress(0f, fixedTime + 4f, awarded: false));
			if (!toothProgress.Awarded)
			{
				float num = toothProgress.Damage + report.damageDealt;
				if (num < report.victim.fullCombinedHealth * 0.25f)
				{
					ToothProgresses[key] = new ToothProgress(num, toothProgress.EndTime, awarded: false);
					return;
				}
				ToothProgresses[key] = new ToothProgress(num, toothProgress.EndTime, awarded: true);
				ToothStacks[attacker.master] = Mathf.Min(10, (!ToothStacks.TryGetValue(attacker.master, out var value2)) ? 1 : (value2 + 1));
			}
		}

		private static void HandleEtherealWeapon(DamageReport report, CharacterBody attacker)
		{
			//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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if (GetStacks(attacker.master, HexId.EtherealWeapon) != 0 && IsSkillDamage(report.damageInfo) && !((ProcChainMask)(ref report.damageInfo.procChainMask)).HasProc((ProcType)26))
			{
				(CharacterBody, HealthComponent) key = (attacker, report.victim);
				if (!EtherealReadyAt.TryGetValue(key, out var value) || !(value > Time.fixedTime))
				{
					EtherealReadyAt[key] = Time.fixedTime + 0.5f;
					DamageInfo damageInfo = report.damageInfo;
					ProcChainMask procChainMask = damageInfo.procChainMask;
					((ProcChainMask)(ref procChainMask)).AddProc((ProcType)26);
					damageInfo.procChainMask = procChainMask;
					damageInfo.procCoefficient = Mathf.Max(1f, damageInfo.procCoefficient);
					GlobalEventManager.instance.OnHitEnemy(damageInfo, ((Component)report.victimBody).gameObject);
				}
			}
		}

		private static void HandleFirebrand(DamageReport report, CharacterBody attacker)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Invalid comparison between Unknown and I4
			//IL_0032: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			if (GetStacks(attacker.master, HexId.Firebrand) != 0 && !(report.damageInfo.procCoefficient <= 0f) && (int)report.damageInfo.dotIndex == -1)
			{
				InflictDotInfo val = new InflictDotInfo
				{
					victimObject = ((Component)report.victimBody).gameObject,
					attackerObject = ((Component)attacker).gameObject,
					dotIndex = (DotIndex)1,
					duration = 5f,
					totalDamage = report.victim.fullCombinedHealth * 0.005f
				};
				DotController.InflictDot(ref val);
			}
		}

		private static void HandleMysticPunch(DamageReport report, CharacterBody attacker)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Invalid comparison between Unknown and I4
			bool flag = report.damageInfo.procChainMask.mask != 0 || (report.damageInfo.procCoefficient < 1f && (int)report.damageInfo.damageType.damageSource == 0);
			if (GetStacks(attacker.master, HexId.MysticPunch) != 0 && flag)
			{
				float fixedTime = Time.fixedTime;
				TriggerWindow value;
				TriggerWindow triggerWindow = ((MysticPunchWindows.TryGetValue(attacker, out value) && value.EndTime > fixedTime) ? value : new TriggerWindow(0, fixedTime + 1f));
				if (triggerWindow.Count < 4)
				{
					MysticPunchWindows[attacker] = new TriggerWindow(triggerWindow.Count + 1, triggerWindow.EndTime);
					RechargeAllSkills(attacker, 0.25f);
				}
			}
		}

		internal static void OnTakeDamageProcess(orig_TakeDamageProcess orig, HealthComponent self, DamageInfo damageInfo)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Invalid comparison between Unknown and I4
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Invalid comparison between Unknown and I4
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Invalid comparison between Unknown and I4
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Invalid comparison between Unknown and I4
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Invalid comparison between Unknown and I4
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkServer.active)
			{
				CharacterBody val = ResolveAttackerBody(damageInfo.attacker);
				if (IsPlayerBody(val))
				{
					DamageSource damageSource = damageInfo.damageType.damageSource;
					if (GetStacks(val.master, HexId.Vulnerability) > 0 && ((damageSource & 0x40) != 0 || (int)damageInfo.dotIndex != -1))
					{
						damageInfo.crit = Util.CheckRoll(val.crit, val.master);
					}
					if (GetStacks(val.master, HexId.BackToBasics) > 0 && ((int)damageSource == 1 || (int)damageSource == 2 || (int)damageSource == 4))
					{
						damageInfo.damage *= 1.5f;
					}
					if (GetStacks(val.master, HexId.GiantSlayer) > 0 && (Object)(object)self.body != (Object)null)
					{
						float num = self.body.bestFitRadius / Mathf.Max(0.1f, val.bestFitRadius);
						if (num > 1f)
						{
							damageInfo.damage *= 1f + Mathf.Clamp(num * 0.1f, 0.1f, 0.3f);
						}
					}
					if (GetStacks(val.master, HexId.ShowYourSword) > 0 && (int)damageInfo.dotIndex == -1 && (Object)(object)self.body != (Object)null && Vector3.Distance(val.corePosition, self.body.corePosition) > 15f)
					{
						return;
					}
					if (GetStacks(val.master, HexId.ToothFairy) > 0 && (Object)(object)val.master != (Object)null && ToothStacks.TryGetValue(val.master, out var value) && Util.CheckRoll((float)value * 10f, val.master))
					{
						damageInfo.damageType |= DamageTypeCombo.op_Implicit((DamageType)2);
					}
				}
				CharacterBody body = self.body;
				if (GetStacks((body != null) ? body.master : null, HexId.NearDeathInsight) > 0 && IsPlayerBody(body) && (Object)(object)body.master != (Object)null && damageInfo.damage >= self.combinedHealth && (!NearDeathReadyAt.TryGetValue(body.master, out var value2) || value2 <= Time.fixedTime))
				{
					NearDeathReadyAt[body.master] = Time.fixedTime + 240f;
					damageInfo.rejected = true;
					orig.Invoke(self, damageInfo);
					self.Heal(Mathf.Max(0f, self.fullCombinedHealth * 0.35f - self.combinedHealth), default(ProcChainMask), true);
					return;
				}
			}
			orig.Invoke(self, damageInfo);
		}

		internal static float OnHeal(orig_Heal orig, HealthComponent self, float amount, ProcChainMask procChainMask, bool nonRegen)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: 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_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: 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)
			//IL_014e: 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_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Expected O, but got Unknown
			CharacterBody body = self.body;
			if (GetStacks((body != null) ? body.master : null, HexId.BackToBasics) > 0 && IsPlayerBody(self.body))
			{
				amount *= 1.5f;
			}
			float num = orig.Invoke(self, amount, procChainMask, nonRegen);
			if (NetworkServer.active && !(num <= 0f))
			{
				CharacterBody body2 = self.body;
				if (GetStacks((body2 != null) ? body2.master : null, HexId.CircleOfDeath) != 0 && IsPlayerBody(self.body))
				{
					CharacterBody body3 = self.body;
					float fixedTime = Time.fixedTime;
					TriggerWindow value;
					TriggerWindow triggerWindow = ((CircleTriggerWindows.TryGetValue(body3, out value) && value.EndTime > fixedTime) ? value : new TriggerWindow(0, fixedTime + 1f));
					if (triggerWindow.Count >= 4)
					{
						return num;
					}
					CircleTriggerWindows[body3] = new TriggerWindow(triggerWindow.Count + 1, triggerWindow.EndTime);
					CharacterBody val = FindClosestEnemy(body3.corePosition);
					if ((Object)(object)((val != null) ? val.healthComponent : null) != (Object)null)
					{
						val.healthComponent.TakeDamage(new DamageInfo
						{
							attacker = ((Component)body3).gameObject,
							inflictor = ((Component)body3).gameObject,
							damage = num * 1.5f,
							position = val.corePosition,
							procCoefficient = 0f,
							damageType = DamageTypeCombo.op_Implicit((DamageType)0),
							damageColorIndex = (DamageColorIndex)3
						});
					}
					return num;
				}
			}
			return num;
		}

		internal static void OnBodyStart(CharacterBody body)
		{
			UpdateMinionScale(body);
			UpdatePlayerScale(body);
		}

		internal static void FixedUpdate()
		{
			if (ExcitedUntil.Count == 0 && TapDancerStates.Count == 0)
			{
				return;
			}
			List<CharacterBody> list = new List<CharacterBody>();
			foreach (KeyValuePair<CharacterBody, float> item in ExcitedUntil)
			{
				if ((Object)(object)item.Key == (Object)null || item.Value <= Time.fixedTime)
				{
					list.Add(item.Key);
				}
			}
			foreach (CharacterBody item2 in list)
			{
				ExcitedUntil.Remove(item2);
				if ((Object)(object)item2 != (Object)null)
				{
					item2.RecalculateStats();
				}
			}
			list.Clear();
			foreach (KeyValuePair<CharacterBody, TimedStackState> tapDancerState in TapDancerStates)
			{
				if ((Object)(object)tapDancerState.Key == (Object)null || tapDancerState.Value.EndTime <= Time.fixedTime)
				{
					list.Add(tapDancerState.Key);
				}
			}
			foreach (CharacterBody item3 in list)
			{
				TapDancerStates.Remove(item3);
				if ((Object)(object)item3 != (Object)null)
				{
					item3.RecalculateStats();
				}
			}
		}

		internal static void ActivateGetExcited(CharacterBody body, float duration)
		{
			ExcitedUntil[body] = Time.fixedTime + duration;
			body.RecalculateStats();
		}

		internal static void ActivateTapDancer(CharacterBody body, int stacks, float duration)
		{
			TapDancerStates[body] = new TimedStackState(Mathf.Clamp(stacks, 1, GetTapDancerStackLimit()), Time.fixedTime + duration);
			body.RecalculateStats();
		}

		private static int GetTapDancerStackLimit()
		{
			return 20 + (Run.instance?.stageClearCount ?? 0) * 10;
		}

		internal static void OnStageBegin()
		{
			ToothStacks.Clear();
			ToothProgresses.Clear();
			RefreshAllBodies();
		}

		internal static void SetShrinkEngineStacks(CharacterMaster master, int stacks)
		{
			ShrinkEngineStacks[master] = Mathf.Max(0, stacks);
			CharacterBody body = master.GetBody();
			if ((Object)(object)body != (Object)null)
			{
				UpdatePlayerScale(body);
				body.RecalculateStats();
			}
		}

		private static int GetShrinkStacks(CharacterMaster master)
		{
			if (!ShrinkEngineStacks.TryGetValue(master, out var value))
			{
				return 0;
			}
			return value;
		}

		private static void SetAndBroadcastShrinkStacks(CharacterMaster master, int stacks)
		{
			SetShrinkEngineStacks(master, stacks);
			NetMessageExtensions.Send((INetMessage)(object)new ShrinkEngineMessage(((Component)master).gameObject, stacks), (NetworkDestination)1);
		}

		internal static void SetTankEngineStacks(CharacterMaster master, int stacks)
		{
			TankEngineStacks[master] = Mathf.Max(0, stacks);
			CharacterBody body = master.GetBody();
			if ((Object)(object)body != (Object)null)
			{
				UpdatePlayerScale(body);
				body.RecalculateStats();
			}
		}

		private static int GetTankStacks(CharacterMaster master)
		{
			if (!TankEngineStacks.TryGetValue(master, out var value))
			{
				return 0;
			}
			return value;
		}

		private static void SetAndBroadcastTankStacks(CharacterMaster master, int stacks)
		{
			SetTankEngineStacks(master, stacks);
			NetMessageExtensions.Send((INetMessage)(object)new TankEngineMessage(((Component)master).gameObject, stacks), (NetworkDestination)1);
		}

		private static IEnumerator DetonateEarthwake(CharacterBody body)
		{
			GameObject attackerObject = ((Component)body).gameObject;
			Vector3 position = body.corePosition;
			yield return (object)new WaitForSeconds(1f);
			if ((Object)(object)attackerObject != (Object)null && (Object)(object)body != (Object)null && (Object)(object)body.healthComponent != (Object)null && body.healthComponent.alive)
			{
				FireBlast(body, position, 3f, 8f, 0.5f);
			}
		}

		private static void FireBlast(CharacterBody attacker, Vector3 position, float damageCoefficient, float radius, float procCoefficient)
		{
			//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)
			//IL_0011: 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)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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_0047: 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_0069: 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)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			new BlastAttack
			{
				attacker = ((Component)attacker).gameObject,
				inflictor = ((Component)attacker).gameObject,
				teamIndex = (TeamIndex)1,
				position = position,
				radius = radius,
				falloffModel = (FalloffModel)0,
				baseDamage = attacker.damage * damageCoefficient,
				baseForce = 1200f,
				crit = Util.CheckRoll(attacker.crit, attacker.master),
				damageType = DamageTypeCombo.op_Implicit((DamageType)0),
				procCoefficient = procCoefficient
			}.Fire();
		}

		private static bool IsSkillDamage(DamageInfo damageInfo)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			DamageSource damageSource = damageInfo.damageType.damageSource;
			if ((int)damageSource != 1 && (int)damageSource != 2 && (int)damageSource != 4)
			{
				return (int)damageSource == 8;
			}
			return true;
		}

		private static bool IsNonPrimarySkillDamage(DamageInfo damageInfo)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			DamageSource damageSource = damageInfo.damageType.damageSource;
			if ((int)damageSource != 2 && (int)damageSource != 4)
			{
				return (int)damageSource == 8;
			}
			return true;
		}

		private static void RechargeAllSkills(CharacterBody body, float seconds)
		{
			SkillLocator skillLocator = body.skillLocator;
			if (!((Object)(object)skillLocator == (Object)null))
			{
				GenericSkill primary = skillLocator.primary;
				if (primary != null)
				{
					primary.RunRecharge(seconds);
				}
				GenericSkill secondary = skillLocator.secondary;
				if (secondary != null)
				{
					secondary.RunRecharge(seconds);
				}
				GenericSkill utility = skillLocator.utility;
				if (utility != null)
				{
					utility.RunRecharge(seconds);
				}
				GenericSkill special = skillLocator.special;
				if (special != null)
				{
					special.RunRecharge(seconds);
				}
			}
		}

		private static void RechargeRandomOtherSkill(CharacterBody body, GenericSkill usedSkill, float seconds)
		{
			SkillLocator skillLocator = body.skillLocator;
			if ((Object)(object)skillLocator == (Object)null || seconds <= 0f)
			{
				return;
			}
			List<GenericSkill> list = new List<GenericSkill>();
			GenericSkill[] array = (GenericSkill[])(object)new GenericSkill[4] { skillLocator.primary, skillLocator.secondary, skillLocator.utility, skillLocator.special };
			foreach (GenericSkill val in array)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)usedSkill && val.cooldownRemaining > 0f)
				{
					list.Add(val);
				}
			}
			if (list.Count > 0)
			{
				list[Random.Range(0, list.Count)].RunRecharge(seconds);
			}
		}

		private static CharacterBody? FindClosestEnemy(Vector3 origin)
		{
			//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_0063: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			CharacterBody result = null;
			float num = float.PositiveInfinity;
			TeamMask enemyTeams = TeamMask.GetEnemyTeams((TeamIndex)1);
			foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList)
			{
				if (!((Object)(object)readOnlyInstances == (Object)null) && !((Object)(object)readOnlyInstances.healthComponent == (Object)null) && readOnlyInstances.healthComponent.alive && !((Object)(object)readOnlyInstances.teamComponent == (Object)null) && ((TeamMask)(ref enemyTeams)).HasTeam(readOnlyInstances.teamComponent.teamIndex))
				{
					Vector3 val = readOnlyInstances.corePosition - origin;
					float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
					if (!(sqrMagnitude >= num))
					{
						result = readOnlyInstances;
						num = sqrMagnitude;
					}
				}
			}
			return result;
		}

		private static bool IsPlayerBody(CharacterBody? body)
		{
			if ((Object)(object)body != (Object)null && (Object)(object)body.master != (Object)null)
			{
				return (Object)(object)body.master.playerCharacterMasterController != (Object)null;
			}
			return false;
		}

		private static CharacterBody? ResolveAttackerBody(GameObject? attackerObject)
		{
			if ((Object)(object)attackerObject == (Object)null)
			{
				return null;
			}
			CharacterBody obj = attackerObject.GetComponent<CharacterBody>();
			if (obj == null)
			{
				obj = attackerObject.GetComponentInParent<CharacterBody>();
				if (obj == null)
				{
					CharacterMaster component = attackerObject.GetComponent<CharacterMaster>();
					if (component == null)
					{
						return null;
					}
					obj = component.GetBody();
				}
			}
			return obj;
		}

		private static bool IsPlayerMinion(CharacterBody body)
		{
			CharacterMaster master = body.master;
			object obj;
			if (master == null)
			{
				obj = null;
			}
			else
			{
				MinionOwnership minionOwnership = master.minionOwnership;
				obj = ((minionOwnership != null) ? minionOwnership.ownerMaster : null);
			}
			CharacterMaster val = (CharacterMaster)obj;
			if ((Object)(object)val != (Object)null)
			{
				return (Object)(object)val.playerCharacterMasterController != (Object)null;
			}
			return false;
		}

		private static void RefreshAllBodies()
		{
			foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList)
			{
				if (!((Object)(object)readOnlyInstances == (Object)null))
				{
					UpdateMinionScale(readOnlyInstances);
					UpdatePlayerScale(readOnlyInstances);
					readOnlyInstances.RecalculateStats();
				}
			}
		}

		private static void UpdateMinionScale(CharacterBody body)
		{
			ModelLocator modelLocator = body.modelLocator;
			Transform val = ((modelLocator != null) ? modelLocator.modelTransform : null);
			if (!((Object)(object)val == (Object)null))
			{
				MinionScaleMarker component = ((Component)val).GetComponent<MinionScaleMarker>();
				CharacterMaster master = body.master;
				object master2;
				if (master == null)
				{
					master2 = null;
				}
				else
				{
					MinionOwnership minionOwnership = master.minionOwnership;
					master2 = ((minionOwnership != null) ? minionOwnership.ownerMaster : null);
				}
				bool flag = GetStacks((CharacterMaster?)master2, HexId.Minionmancer) > 0 && IsPlayerMinion(body);
				if (flag && (Object)(object)component == (Object)null)
				{
					((Component)val).gameObject.AddComponent<MinionScaleMarker>();
				}
				else if (!flag && (Object)(object)component != (Object)null)
				{
					Object.Destroy((Object)(object)component);
				}
			}
		}

		private static void UpdatePlayerScale(CharacterBody body)
		{
			if (!IsPlayerBody(body))
			{
				return;
			}
			ModelLocator modelLocator = body.modelLocator;
			Transform val = ((modelLocator != null) ? modelLocator.modelTransform : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			float num = 1f;
			if (GetStacks(body.master, HexId.Goliath) > 0)
			{
				num *= 1.5f;
			}
			if ((Object)(object)body.master != (Object)null && ShrinkEngineStacks.TryGetValue(body.master, out var value))
			{
				num *= Mathf.Max(0.35f, Mathf.Pow(0.95f, (float)value));
			}
			if ((Object)(object)body.master != (Object)null && TankEngineStacks.TryGetValue(body.master, out var value2))
			{
				num *= 1f + (float)value2 * 0.1f;
			}
			if (GetStacks(body.master, HexId.GiantSlayer) > 0)
			{
				num *= 0.75f;
			}
			PlayerScaleMarker playerScaleMarker = ((Component)val).GetComponent<PlayerScaleMarker>();
			if (Mathf.Approximately(num, 1f))
			{
				if ((Object)(object)playerScaleMarker != (Object)null)
				{
					Object.Destroy((Object)(object)playerScaleMarker);
				}
				return;
			}
			if (playerScaleMarker == null)
			{
				playerScaleMarker = ((Component)val).gameObject.AddComponent<PlayerScaleMarker>();
			}
			playerScaleMarker.SetScale(num);
		}

		private static void ClearRuntimeEffects()
		{
			ExcitedUntil.Clear();
			TapDancerStates.Clear();
			InfernalNextRecharge.Clear();
			CircleTriggerWindows.Clear();
			ShrinkEngineStacks.Clear();
			TankEngineStacks.Clear();
			ToothStacks.Clear();
			ToothProgresses.Clear();
			NearDeathReadyAt.Clear();
			EtherealReadyAt.Clear();
			MysticPunchWindows.Clear();
			DropkickExecuting.Clear();
			foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList)
			{
				object obj;
				if (readOnlyInstances == null)
				{
					obj = null;
				}
				else
				{
					ModelLocator modelLocator = readOnlyInstances.modelLocator;
					if (modelLocator == null)
					{
						obj = null;
					}
					else
					{
						Transform modelTransform = modelLocator.modelTransform;
						obj = ((modelTransform != null) ? ((Component)modelTransform).GetComponent<MinionScaleMarker>() : null);
					}
				}
				MinionScaleMarker minionScaleMarker = (MinionScaleMarker)obj;
				if ((Object)(object)minionScaleMarker != (Object)null)
				{
					Object.Destroy((Object)(object)minionScaleMarker);
				}
				object obj2;
				if (readOnlyInstances == null)
				{
					obj2 = null;
				}
				else
				{
					ModelLocator modelLocator2 = readOnlyInstances.modelLocator;
					if (modelLocator2 == null)
					{
						obj2 = null;
					}
					else
					{
						Transform modelTransform2 = modelLocator2.modelTransform;
						obj2 = ((modelTransform2 != null) ? ((Component)modelTransform2).GetComponent<PlayerScaleMarker>() : null);
					}
				}
				PlayerScaleMarker playerScaleMarker = (PlayerScaleMarker)obj2;
				if ((Object)(object)playerScaleMarker != (Object)null)
				{
					Object.Destroy((Object)(object)playerScaleMarker);
				}
			}
		}
	}
	internal sealed class MinionScaleMarker : MonoBehaviour
	{
		private Vector3 _originalScale;

		private void Awake()
		{
			//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)
			//IL_0018: 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)
			_originalScale = ((Component)this).transform.localScale;
			((Component)this).transform.localScale = _originalScale * 2.5f;
		}

		private void OnDestroy()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((Component)this).transform != (Object)null)
			{
				((Component)this).transform.localScale = _originalScale;
			}
		}
	}
	internal sealed class PlayerScaleMarker : MonoBehaviour
	{
		private Vector3 _originalScale;

		private void Awake()
		{
			//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)
			_originalScale = ((Component)this).transform.localScale;
		}

		internal void SetScale(float multiplier)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			((Component)this).transform.localScale = _originalScale * multiplier;
		}

		private void OnDestroy()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((Component)this).transform != (Object)null)
			{
				((Component)this).transform.localScale = _originalScale;
			}
		}
	}
	internal readonly struct TimedStackState
	{
		internal int Stacks { get; }

		internal float EndTime { get; }

		internal TimedStackState(int stacks, float endTime)
		{
			Stacks = stacks;
			EndTime = endTime;
		}
	}
	internal readonly struct TriggerWindow
	{
		internal int Count { get; }

		internal float EndTime { get; }

		internal TriggerWindow(int count, float endTime)
		{
			Count = count;
			EndTime = endTime;
		}
	}
	internal readonly struct ToothProgress
	{
		internal float Damage { get; }

		internal float EndTime { get; }

		internal bool Awarded { get; }

		internal ToothProgress(float damage, float endTime, bool awarded)
		{
			Damage = damage;
			EndTime = endTime;
			Awarded = awarded;
		}
	}
	internal sealed class HexStateMessage : INetMessage, ISerializableObject
	{
		private GameObject? _masterObject;

		private readonly List<KeyValuePair<HexId, int>> _values = new List<KeyValuePair<HexId, int>>();

		public HexStateMessage()
		{
		}

		internal HexStateMessage(GameObject masterObject, IEnumerable<KeyValuePair<HexId, int>> values)
		{
			_masterObject = masterObject;
			_values.AddRange(values);
		}

		public void Serialize(NetworkWriter writer)
		{
			writer.Write(_masterObject);
			writer.Write((byte)_values.Count);
			foreach (KeyValuePair<HexId, int> value in _values)
			{
				writer.Write((byte)value.Key);
				writer.Write(value.Value);
			}
		}

		public void Deserialize(NetworkReader reader)
		{
			_masterObject = reader.ReadGameObject();
			_values.Clear();
			byte b = reader.ReadByte();
			for (int i = 0; i < b; i++)
			{
				_values.Add(new KeyValuePair<HexId, int>((HexId)reader.ReadByte(), reader.ReadInt32()));
			}
		}

		public void OnReceived()
		{
			CharacterMaster val = (((Object)(object)_masterObject != (Object)null) ? _masterObject.GetComponent<CharacterMaster>() : null);
			if ((Object)(object)val != (Object)null)
			{
				HexRunState.Replace(val, _values);
			}
		}
	}
	internal sealed class OpenHexPickerMessage : INetMessage, ISerializableObject
	{
		private GameObject? _masterObject;

		private int _rerolls;

		public OpenHexPickerMessage()
		{
		}

		internal OpenHexPickerMessage(GameObject masterObject, int rerolls)
		{
			_masterObject = masterObject;
			_rerolls = rerolls;
		}

		public void Serialize(NetworkWriter writer)
		{
			writer.Write(_masterObject);
			writer.Write(_rerolls);
		}

		public void Deserialize(NetworkReader reader)
		{
			_masterObject = reader.ReadGameObject();
			_rerolls = reader.ReadInt32();
		}

		public void OnReceived()
		{
			CharacterMaster val = (((Object)(object)_masterObject != (Object)null) ? _masterObject.GetComponent<CharacterMaster>() : null);
			if ((Object)(object)val != (Object)null)
			{
				Plugin.Instance.OpenPicker(val, _rerolls);
			}
		}
	}
	internal sealed class SelectHexMessage : INetMessage, ISerializableObject
	{
		private GameObject? _masterObject;

		private HexId _hexId;

		public SelectHexMessage()
		{
		}

		internal SelectHexMessage(GameObject masterObject, HexId hexId)
		{
			_masterObject = masterObject;
			_hexId = hexId;
		}

		public void Serialize(NetworkWriter writer)
		{
			writer.Write(_masterObject);
			writer.Write((byte)_hexId);
		}

		public void Deserialize(NetworkReader reader)
		{
			_masterObject = reader.ReadGameObject();
			_hexId = (HexId)reader.ReadByte();
		}

		public void OnReceived()
		{
			if (NetworkServer.active)
			{
				CharacterMaster val = (((Object)(object)_masterObject != (Object)null) ? _masterObject.GetComponent<CharacterMaster>() : null);
				if ((Object)(object)val != (Object)null)
				{
					Plugin.Instance.SelectHex(val, _hexId);
				}
			}
		}
	}
	internal sealed class GetExcitedMessage : INetMessage, ISerializableObject
	{
		private GameObject? _bodyObject;

		private float _duration;

		public GetExcitedMessage()
		{
		}

		internal GetExcitedMessage(GameObject bodyObject, float duration)
		{
			_bodyObject = bodyObject;
			_duration = duration;
		}

		public void Serialize(NetworkWriter writer)
		{
			writer.Write(_bodyObject);
			writer.Write(_duration);
		}

		public void Deserialize(NetworkReader reader)
		{
			_bodyObject = reader.ReadGameObject();
			_duration = reader.ReadSingle();
		}

		public void OnReceived()
		{
			CharacterBody val = (((Object)(object)_bodyObject != (Object)null) ? _bodyObject.GetComponent<CharacterBody>() : null);
			if ((Object)(object)val != (Object)null)
			{
				HexRunState.ActivateGetExcited(val, _duration);
			}
		}
	}
	internal sealed class TapDancerMessage : INetMessage, ISerializableObject
	{
		private GameObject? _bodyObject;

		private int _stacks;

		private float _duration;

		public TapDancerMessage()
		{
		}

		internal TapDancerMessage(GameObject bodyObject, int stacks, float duration)
		{
			_bodyObject = bodyObject;
			_stacks = stacks;
			_duration = duration;
		}

		public void Serialize(NetworkWriter writer)
		{
			writer.Write(_bodyObject);
			writer.Write(_stacks);
			writer.Write(_duration);
		}

		public void Deserialize(NetworkReader reader)
		{
			_bodyObject = reader.ReadGameObject();
			_stacks = reader.ReadInt32();
			_duration = reader.ReadSingle();
		}

		public void OnReceived()
		{
			CharacterBody val = (((Object)(object)_bodyObject != (Object)null) ? _bodyObject.GetComponent<CharacterBody>() : null);
			if ((Object)(object)val != (Object)null)
			{
				HexRunState.ActivateTapDancer(val, _stacks, _duration);
			}
		}
	}
	internal sealed class ShrinkEngineMessage : INetMessage, ISerializableObject
	{
		private GameObject? _masterObject;

		private int _stacks;

		public ShrinkEngineMessage()
		{
		}

		internal ShrinkEngineMessage(GameObject masterObject, int stacks)
		{
			_masterObject = masterObject;
			_stacks = stacks;
		}

		public void Serialize(NetworkWriter writer)
		{
			writer.Write(_masterObject);
			writer.Write(_stacks);
		}

		public void Deserialize(NetworkReader reader)
		{
			_masterObject = reader.ReadGameObject();
			_stacks = reader.ReadInt32();
		}

		public void OnReceived()
		{
			CharacterMaster val = (((Object)(object)_masterObject != (Object)null) ? _masterObject.GetComponent<CharacterMaster>() : null);
			if ((Object)(object)val != (Object)null)
			{
				HexRunState.SetShrinkEngineStacks(val, _stacks);
			}
		}
	}
	internal sealed class TankEngineMessage : INetMessage, ISerializableObject
	{
		private GameObject? _masterObject;

		private int _stacks;

		public TankEngineMessage()
		{
		}

		internal TankEngineMessage(GameObject masterObject, int stacks)
		{
			_masterObject = masterObject;
			_stacks = stacks;
		}

		public void Serialize(NetworkWriter writer)
		{
			writer.Write(_masterObject);
			writer.Write(_stacks);
		}

		public void Deserialize(NetworkReader reader)
		{
			_masterObject = reader.ReadGameObject();
			_stacks = reader.ReadInt32();
		}

		public void OnReceived()
		{
			CharacterMaster val = (((Object)(object)_masterObject != (Object)null) ? _masterObject.GetComponent<CharacterMaster>() : null);
			if ((Object)(object)val != (Object)null)
			{
				HexRunState.SetTankEngineStacks(val, _stacks);
			}
		}
	}
	[BepInPlugin("com.dmh.hexedrisk", "HexedRisk", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static StatHookEventHandler <0>__ApplyStats;

			public static Action<DamageReport> <1>__OnCharacterDeath;

			public static Action<DamageReport> <2>__OnServerDamageDealt;

			public static Action<CharacterBody> <3>__OnBodyStart;

			public static hook_ExecuteIfReady <4>__OnSkillExecute;

			public static hook_Heal <5>__OnHeal;

			public static hook_TakeDamageProcess <6>__OnTakeDamageProcess;
		}

		public const string PluginGuid = "com.dmh.hexedrisk";

		public const string PluginName = "HexedRisk";

		public const string PluginVersion = "1.0.1";

		private ConfigEntry<int> _rerollsPerStage;

		private ConfigEntry<bool> _showActiveHexes;

		private HexPickerUI _picker;

		private int _lastBossGroupId = int.MinValue;

		private bool _hexChoicePending;

		private bool _waitingForSelection;

		private bool _continuationScheduled;

		private readonly HashSet<CharacterMaster> _pendingPlayers = new HashSet<CharacterMaster>();

		private Stage? _pendingStage;

		private SceneDef? _pendingDestination;

		internal static ManualLogSource Log { get; private set; }

		internal static Plugin Instance { get; private set; }

		private void Awake()
		{
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Expected O, but got Unknown
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Expected O, but got Unknown
			//IL_019f: 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_01aa: Expected O, but got Unknown
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Expected O, but got Unknown
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			_rerollsPerStage = ((BaseUnityPlugin)this).Config.Bind<int>("General", "RerollsPerStage", 3, "每次击败传送器 Boss 后可刷新的次数。范围 0-99。");
			_showActiveHexes = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowActiveHexes", true, "在屏幕左上角显示本局已选海克斯;游戏内按 F7 临时隐藏。");
			_picker = new HexPickerUI(SubmitHex, _showActiveHexes);
			NetworkingAPI.RegisterMessageType<HexStateMessage>();
			NetworkingAPI.RegisterMessageType<OpenHexPickerMessage>();
			NetworkingAPI.RegisterMessageType<SelectHexMessage>();
			NetworkingAPI.RegisterMessageType<GetExcitedMessage>();
			NetworkingAPI.RegisterMessageType<TapDancerMessage>();
			NetworkingAPI.RegisterMessageType<ShrinkEngineMessage>();
			NetworkingAPI.RegisterMessageType<TankEngineMessage>();
			Run.onRunStartGlobal += OnRunStart;
			Run.onRunDestroyGlobal += OnRunDestroy;
			Stage.onServerStageBegin += OnServerStageBegin;
			BossGroup.onBossGroupDefeatedServer += OnBossGroupDefeatedServer;
			NetworkUser.onNetworkUserDiscovered += new NetworkUserGenericDelegate(OnNetworkUserDiscovered);
			object obj = <>O.<0>__ApplyStats;
			if (obj == null)
			{
				StatHookEventHandler val = HexRunState.ApplyStats;
				<>O.<0>__ApplyStats = val;
				obj = (object)val;
			}
			RecalculateStatsAPI.GetStatCoefficients += (StatHookEventHandler)obj;
			GlobalEventManager.onCharacterDeathGlobal += HexRunState.OnCharacterDeath;
			GlobalEventManager.onServerDamageDealt += HexRunState.OnServerDamageDealt;
			CharacterBody.onBodyStartGlobal += HexRunState.OnBodyStart;
			object obj2 = <>O.<4>__OnSkillExecute;
			if (obj2 == null)
			{
				hook_ExecuteIfReady val2 = HexRunState.OnSkillExecute;
				<>O.<4>__OnSkillExecute = val2;
				obj2 = (object)val2;
			}
			GenericSkill.ExecuteIfReady += (hook_ExecuteIfReady)obj2;
			object obj3 = <>O.<5>__OnHeal;
			if (obj3 == null)
			{
				hook_Heal val3 = HexRunState.OnHeal;
				<>O.<5>__OnHeal = val3;
				obj3 = (object)val3;
			}
			HealthComponent.Heal += (hook_Heal)obj3;
			object obj4 = <>O.<6>__OnTakeDamageProcess;
			if (obj4 == null)
			{
				hook_TakeDamageProcess val4 = HexRunState.OnTakeDamageProcess;
				<>O.<6>__OnTakeDamageProcess = val4;
				obj4 = (object)val4;
			}
			HealthComponent.TakeDamageProcess += (hook_TakeDamageProcess)obj4;
			Stage.BeginAdvanceStage += new hook_BeginAdvanceStage(OnBeginAdvanceStage);
			Log.LogInfo((object)"HexedRisk 1.0.1 loaded.");
		}

		private void OnDestroy()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_0065: 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_0070: Expected O, but got Unknown
			//IL_00e5: 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_00f0: Expected O, but got Unknown
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Expected O, but got Unknown
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Expected O, but got Unknown
			Run.onRunStartGlobal -= OnRunStart;
			Run.onRunDestroyGlobal -= OnRunDestroy;
			Stage.onServerStageBegin -= OnServerStageBegin;
			BossGroup.onBossGroupDefeatedServer -= OnBossGroupDefeatedServer;
			NetworkUser.onNetworkUserDiscovered -= new NetworkUserGenericDelegate(OnNetworkUserDiscovered);
			object obj = <>O.<0>__ApplyStats;
			if (obj == null)
			{
				StatHookEventHandler val = HexRunState.ApplyStats;
				<>O.<0>__ApplyStats = val;
				obj = (object)val;
			}
			RecalculateStatsAPI.GetStatCoefficients -= (StatHookEventHandler)obj;
			GlobalEventManager.onCharacterDeathGlobal -= HexRunState.OnCharacterDeath;
			GlobalEventManager.onServerDamageDealt -= HexRunState.OnServerDamageDealt;
			CharacterBody.onBodyStartGlobal -= HexRunState.OnBodyStart;
			object obj2 = <>O.<4>__OnSkillExecute;
			if (obj2 == null)
			{
				hook_ExecuteIfReady val2 = HexRunState.OnSkillExecute;
				<>O.<4>__OnSkillExecute = val2;
				obj2 = (object)val2;
			}
			GenericSkill.ExecuteIfReady -= (hook_ExecuteIfReady)obj2;
			object obj3 = <>O.<5>__OnHeal;
			if (obj3 == null)
			{
				hook_Heal val3 = HexRunState.OnHeal;
				<>O.<5>__OnHeal = val3;
				obj3 = (object)val3;
			}
			HealthComponent.Heal -= (hook_Heal)obj3;
			object obj4 = <>O.<6>__OnTakeDamageProcess;
			if (obj4 == null)
			{
				hook_TakeDamageProcess val4 = HexRunState.OnTakeDamageProcess;
				<>O.<6>__OnTakeDamageProcess = val4;
				obj4 = (object)val4;
			}
			HealthComponent.TakeDamageProcess -= (hook_TakeDamageProcess)obj4;
			Stage.BeginAdvanceStage -= new hook_BeginAdvanceStage(OnBeginAdvanceStage);
			_picker?.Close();
		}

		private void Update()
		{
			_picker.Update();
		}

		private void FixedUpdate()
		{
			HexRunState.FixedUpdate();
			if (_waitingForSelection && NetworkServer.active)
			{
				_pendingPlayers.RemoveWhere((CharacterMaster master) => (Object)(object)master == (Object)null);
				if (_pendingPlayers.Count == 0)
				{
					ScheduleContinueToNextStage();
				}
			}
		}

		private void OnGUI()
		{
			_picker.Draw();
		}

		private void OnRunStart(Run run)
		{
			_lastBossGroupId = int.MinValue;
			ClearPendingChoice();
			_picker.Close();
			HexRunState.Reset();
		}

		private void OnRunDestroy(Run run)
		{
			ClearPendingChoice();
			_picker.Close();
			HexRunState.Reset();
		}

		private void OnServerStageBegin(Stage stage)
		{
			_lastBossGroupId = int.MinValue;
			ClearPendingChoice();
			HexRunState.OnStageBegin();
			foreach (KeyValuePair<CharacterMaster, IEnumerable<KeyValuePair<HexId, int>>> item in HexRunState.EnumeratePlayers())
			{
				BroadcastState(item.Key);
			}
		}

		private void OnNetworkUserDiscovered(NetworkUser networkUser)
		{
			if (!NetworkServer.active || (Object)(object)networkUser == (Object)null || ((NetworkBehaviour)networkUser).connectionToClient == null)
			{
				return;
			}
			foreach (KeyValuePair<CharacterMaster, IEnumerable<KeyValuePair<HexId, int>>> item in HexRunState.EnumeratePlayers())
			{
				NetMessageExtensions.Send((INetMessage)(object)new HexStateMessage(((Component)item.Key).gameObject, item.Value), ((NetworkBehaviour)networkUser).connectionToClient);
			}
		}

		private void OnBossGroupDefeatedServer(BossGroup bossGroup)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			if (!NetworkServer.active || (Object)(object)bossGroup == (Object)null)
			{
				return;
			}
			TeleporterInteraction instance = TeleporterInteraction.instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.bossGroup != (Object)(object)bossGroup))
			{
				int instanceID = ((Object)bossGroup).GetInstanceID();
				if (_lastBossGroupId != instanceID)
				{
					_lastBossGroupId = instanceID;
					_hexChoicePending = true;
					Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
					{
						baseToken = "<style=cIsUtility>海克斯已就绪:</style>使用已充能的传送器离开时进行选择。"
					});
				}
			}
		}

		private void OnBeginAdvanceStage(orig_BeginAdvanceStage orig, Stage self, SceneDef destinationScene)
		{
			if (!NetworkServer.active || !_hexChoicePending)
			{
				orig.Invoke(self, destinationScene);
			}
			else
			{
				if (_waitingForSelection || _continuationScheduled)
				{
					return;
				}
				_waitingForSelection = true;
				_pendingStage = self;
				_pendingDestination = destinationScene;
				_pendingPlayers.Clear();
				foreach (NetworkUser readOnlyInstances in NetworkUser.readOnlyInstancesList)
				{
					CharacterMaster val = ((readOnlyInstances != null) ? readOnlyInstances.master : null);
					if ((Object)(object)val != (Object)null && HexCatalog.HasAvailable(val))
					{
						_pendingPlayers.Add(val);
					}
				}
				if (_pendingPlayers.Count != 0)
				{
					int rerolls = Mathf.Clamp(_rerollsPerStage.Value, 0, 99);
					{
						foreach (NetworkUser readOnlyInstances2 in NetworkUser.readOnlyInstancesList)
						{
							CharacterMaster val2 = ((readOnlyInstances2 != null) ? readOnlyInstances2.master : null);
							if (!((Object)(object)val2 == (Object)null) && _pendingPlayers.Contains(val2))
							{
								if (((NetworkBehaviour)readOnlyInstances2).connectionToClient != null)
								{
									NetMessageExtensions.Send((INetMessage)(object)new OpenHexPickerMessage(((Component)val2).gameObject, rerolls), ((NetworkBehaviour)readOnlyInstances2).connectionToClient);
								}
								else if (!Application.isBatchMode)
								{
									OpenPicker(val2, rerolls);
								}
								else
								{
									SelectHex(val2, HexCatalog.RollThree(val2, new Random())[0].Id);
								}
							}
						}
						return;
					}
				}
				ClearPendingChoice();
				orig.Invoke(self, destinationScene);
			}
		}

		internal void OpenPicker(CharacterMaster master, int rerolls)
		{
			_picker.Open(master, rerolls);
		}

		private void SubmitHex(CharacterMaster master, HexId id)
		{
			if (NetworkServer.active)
			{
				SelectHex(master, id);
			}
			else
			{
				NetMessageExtensions.Send((INetMessage)(object)new SelectHexMessage(((Component)master).gameObject, id), (NetworkDestination)2);
			}
		}

		internal void SelectHex(CharacterMaster master, HexId id)
		{
			//IL_005c: 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_009d: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			if (NetworkServer.active && !((Object)(object)master == (Object)null) && _pendingPlayers.Contains(master) && Enum.IsDefined(typeof(HexId), id) && HexRunState.GetStacks(master, id) <= 0)
			{
				HexRunState.Add(master, id);
				BroadcastState(master);
				HexDefinition hexDefinition = HexCatalog.Get(id);
				int stacks = HexRunState.GetStacks(master, id);
				Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
				{
					baseToken = ((stacks > 0) ? $"<style=cIsUtility>一名玩家获得海克斯:</style><style=cIsDamage>{hexDefinition.Name}</style> ×{stacks}" : ("<style=cIsUtility>一名玩家触发海克斯:</style><style=cIsDamage>" + hexDefinition.Name + "</style>"))
				});
				Log.LogInfo((object)$"Player {((NetworkBehaviour)master).netId} selected hex {id}; stacks={stacks}.");
				_pendingPlayers.Remove(master);
				if (_waitingForSelection && _pendingPlayers.Count == 0)
				{
					ScheduleContinueToNextStage();
				}
			}
		}

		private void ScheduleContinueToNextStage()
		{
			if (!_continuationScheduled)
			{
				_continuationScheduled = true;
				((MonoBehaviour)this).StartCoroutine(ContinueToNextStage());
			}
		}

		private IEnumerator ContinueToNextStage()
		{
			yield return null;
			Stage pendingStage = _pendingStage;
			SceneDef pendingDestination = _pendingDestination;
			_waitingForSelection = false;
			_continuationScheduled = false;
			_hexChoicePending = false;
			_pendingStage = null;
			_pendingDestination = null;
			if ((Object)(object)pendingStage != (Object)null && (Object)(object)pendingDestination != (Object)null)
			{
				pendingStage.BeginAdvanceStage(pendingDestination);
			}
		}

		internal Coroutine StartManagedCoroutine(IEnumerator routine)
		{
			return ((MonoBehaviour)this).StartCoroutine(routine);
		}

		private void ClearPendingChoice()
		{
			_hexChoicePending = false;
			_waitingForSelection = false;
			_continuationScheduled = false;
			_pendingPlayers.Clear();
			_pendingStage = null;
			_pendingDestination = null;
		}

		private static void BroadcastState(CharacterMaster master)
		{
			if (NetworkServer.active)
			{
				NetMessageExtensions.Send((INetMessage)(object)new HexStateMessage(((Component)master).gameObject, HexRunState.Enumerate(master)), (NetworkDestination)1);
			}
		}
	}
}