Decompiled source of EliteCreaturesReborn v3.36.0

plugins\EliteCreaturesReborn.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using BundlePrefabs;
using Charter;
using ConfigReload;
using EliteCraftingLink;
using EliteCreaturesReborn.Altars;
using EliteCreaturesReborn.Arena;
using EliteCreaturesReborn.Arena.Gate;
using EliteCreaturesReborn.Arena.Hall;
using EliteCreaturesReborn.Arena.Rewards;
using EliteCreaturesReborn.Arena.Travel;
using EliteCreaturesReborn.Arena.Trial;
using EliteCreaturesReborn.Aspects;
using EliteCreaturesReborn.Breeding;
using EliteCreaturesReborn.Commands;
using EliteCreaturesReborn.Compendium;
using EliteCreaturesReborn.Config;
using EliteCreaturesReborn.Creatures.BatFiend;
using EliteCreaturesReborn.Display;
using EliteCreaturesReborn.Hints;
using EliteCreaturesReborn.Horde;
using EliteCreaturesReborn.Loot;
using EliteCreaturesReborn.Mutations;
using EliteCreaturesReborn.Patches;
using EliteCreaturesReborn.Raids;
using EliteCreaturesReborn.Recap;
using EliteCreaturesReborn.Recap.Window;
using EliteCreaturesReborn.Rendering;
using EliteCreaturesReborn.Rules;
using EliteCreaturesReborn.Runtime;
using EliteCreaturesReborn.Scaling;
using EliteCreaturesReborn.Tally;
using EliteCreaturesReborn.Taming;
using EliteCreaturesReborn.Traits;
using EliteCreaturesReborn.Util;
using EliteCreaturesReborn.Visuals;
using HarmonyLib;
using Hotkeys;
using LocalEffects;
using Microsoft.CodeAnalysis;
using PatchGuard;
using PlateColumn;
using PlayerGrid;
using RecipeCounts;
using StatusTemplates;
using TMPro;
using Translations;
using Unity.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using WindowInput;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.RepresentationModel;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Callbacks;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Gerald Glasgow")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) Gerald Glasgow. Licensed under the GNU General Public License v3.0.")]
[assembly: AssemblyDescription("Elite Creatures Reborn: named, visible mutations that make every creature a different fight")]
[assembly: AssemblyFileVersion("3.36.0.0")]
[assembly: AssemblyInformationalVersion("3.36.0+0fc4cd5425184492114823d48d99397018a1a46b")]
[assembly: AssemblyProduct("Elite Creatures Reborn")]
[assembly: AssemblyTitle("EliteCreaturesReborn")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("3.36.0.0")]
[module: UnverifiableCode]
[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 EliteCreaturesReborn
{
	[BepInPlugin("gglasgow.elitecreaturesreborn", "Elite Creatures Reborn", "3.36.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		private void Awake()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			Log.Bind(((BaseUnityPlugin)this).Logger);
			ConfigReloader.HoldSaves(((BaseUnityPlugin)this).Config);
			Configuration.BindAll(((BaseUnityPlugin)this).Config);
			RuleFile.Initialise();
			ServerLock.Setup("gglasgow.elitecreaturesreborn", "Elite Creatures Reborn", "3.36.0");
			Harmony val = new Harmony("gglasgow.elitecreaturesreborn");
			val.PatchAll(typeof(Plugin).Assembly);
			Lang.Install(val, typeof(Plugin).Assembly, "EliteCreaturesReborn", ((BaseUnityPlugin)this).Logger);
			AnyQuality.Install(val);
			RecapHost.Attach(((Component)this).gameObject, val);
			GameWindow.Add(() => AltarWindow.IsOpen, AltarWindow.Close);
			((Component)this).gameObject.AddComponent<TallyFlush>();
			RaidMarker.Setup(val);
			BatFiendPrefabs.Install(val);
			((Component)this).gameObject.AddComponent<RaidTicker>();
			((Component)this).gameObject.AddComponent<TameTicker>();
			ServerLock.Install(val);
			Guard.Install(val, ((BaseUnityPlugin)this).Logger, typeof(Plugin).Assembly);
			ConfigReloader.Setup(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
			RuleReload.Attach();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Elite Creatures Reborn 3.36.0 ready.");
		}
	}
	internal static class PluginInfo
	{
		public const string Guid = "gglasgow.elitecreaturesreborn";

		public const string Name = "Elite Creatures Reborn";

		public const string PluginVersion = "3.36.0";

		public const string Author = "Gerald Glasgow";

		public const string Licence = "GNU General Public License v3.0";
	}
}
namespace EliteCreaturesReborn.Visuals
{
	public static class CosmeticClone
	{
		public static GameObject? Spawn(GameObject? prefab, Transform parent, Vector3 position, bool endless)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (!Machine.Headless)
			{
				return LocalEffect.Attach(prefab, parent, position, endless, Density());
			}
			return null;
		}

		public static void Flash(GameObject? prefab, Vector3 position, float radius)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (!Machine.Headless)
			{
				LocalEffect.Flash(prefab, position, radius, Density());
			}
		}

		public static void FlashWhole(GameObject? prefab, Vector3 position, float radius, float scale)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (!Machine.Headless)
			{
				LocalEffect.FlashWhole(prefab, position, radius, scale, Density());
			}
		}

		public static void Sound(GameObject? prefab, Vector3 position)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (!Machine.Headless)
			{
				LocalEffect.Sound(prefab, position);
			}
		}

		public static void SoundOnly(GameObject? prefab, Vector3 position, float volume)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			if (!Machine.Headless)
			{
				LocalEffect.SoundOnly(prefab, position, volume);
			}
		}

		private static float Density()
		{
			return Mathf.Clamp01(Configuration.EffectDensity.Value);
		}
	}
	public static class EffectResolver
	{
		public static readonly string[] Cloud = new string[7] { "poison", "blob", "ooze", "puke", "gas", "spore", "smoke" };

		public static readonly string[] Blast = new string[7] { "explos", "blast", "fire", "bomb", "death", "burst", "flame" };

		public static readonly string[] BlastSound = new string[3] { "explo", "bomb", "blast" };

		public static readonly string[] Warning = new string[6] { "smoke", "fire", "burn", "charge", "glow", "spark" };

		public static readonly string[] Reflect = new string[6] { "staffshield_hit", "shield", "spark", "hit", "block", "staff" };

		public static readonly string[] Devour = new string[7] { "aspect_death", "death", "gore", "corpse", "destr", "blood", "hit" };

		public static readonly string[] Steal = new string[6] { "steal", "pickpocket", "pocket", "grab", "loot", "coin" };

		public static readonly string[] Summon = new string[5] { "spawn", "summon", "portal", "smoke", "puff" };

		public static readonly string[] Phantom = new string[6] { "ghost", "wisp", "puff", "smoke", "vanish", "poof" };

		private const string SoundKey = "sound:";

		private static readonly Dictionary<string, GameObject?> Cache = new Dictionary<string, GameObject>();

		public static GameObject? Resolve(string name, string[] keywords, string setting = "")
		{
			return Lookup(name, keywords, setting, sound: false);
		}

		public static GameObject? ResolveSound(string name, string[] keywords, string setting = "")
		{
			return Lookup(name, keywords, setting, sound: true);
		}

		public static GameObject? ForRole(string role)
		{
			switch (role)
			{
			case "reflect":
			case "devour":
				return ByKeyword(role, (role == "reflect") ? Reflect : Devour);
			case "summon":
			case "phantom":
				return ByKeyword(role, (role == "summon") ? Summon : Phantom);
			default:
				return null;
			case "steal":
				return ByKeyword(role, Steal);
			}
		}

		public static GameObject? ByKeyword(string role, string[] keywords)
		{
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			if (Cache.TryGetValue(role, out GameObject value))
			{
				return value;
			}
			GameObject val = Nearest(instance, keywords, sound: false);
			if ((Object)(object)val == (Object)null)
			{
				Log.Warn("no vanilla effect matched the " + role + " tell; it will not be shown");
			}
			else if (Log.Diagnostics)
			{
				Log.Diag("the " + role + " tell is " + ((Object)val).name);
			}
			Cache[role] = val;
			return val;
		}

		public static IEnumerable<GameObject> Prefabs(ZNetScene scene)
		{
			foreach (GameObject prefab in scene.m_prefabs)
			{
				yield return prefab;
			}
			foreach (GameObject nonNetViewPrefab in scene.m_nonNetViewPrefabs)
			{
				yield return nonNetViewPrefab;
			}
		}

		public static bool IsEffectName(GameObject? prefab)
		{
			if ((Object)(object)prefab != (Object)null)
			{
				if (!Named(prefab, sound: false))
				{
					return Named(prefab, sound: true);
				}
				return true;
			}
			return false;
		}

		private static GameObject? Lookup(string name, string[] keywords, string setting, bool sound)
		{
			ZNetScene instance = ZNetScene.instance;
			if ((Object)(object)instance == (Object)null || string.IsNullOrEmpty(name))
			{
				return null;
			}
			string key = (sound ? ("sound:" + name) : name);
			if (Cache.TryGetValue(key, out GameObject value))
			{
				return value;
			}
			GameObject val = Find(instance, name, keywords, setting, sound);
			Cache[key] = val;
			return val;
		}

		private static GameObject? Find(ZNetScene scene, string name, string[] keywords, string setting, bool sound)
		{
			GameObject val = Fits(scene.GetPrefab(name), sound);
			if ((Object)(object)val != (Object)null)
			{
				return val;
			}
			string text = (string.IsNullOrEmpty(setting) ? "" : (" (from setting '" + setting + "')"));
			GameObject val2 = Nearest(scene, keywords, sound);
			Log.Warn(((Object)(object)val2 != (Object)null) ? ("effect prefab '" + name + "'" + text + " not found; falling back to '" + ((Object)val2).name + "'") : ("effect prefab '" + name + "'" + text + " not found and no fallback effect exists - it stays " + (sound ? "silent" : "invisible")));
			return val2;
		}

		private static GameObject? Nearest(ZNetScene scene, string[] keywords, bool sound)
		{
			foreach (string value in keywords)
			{
				foreach (GameObject item in Prefabs(scene))
				{
					if ((Object)(object)item != (Object)null && Named(item, sound) && ((Object)item).name.ToLowerInvariant().Contains(value) && (Object)(object)Fits(item, sound) != (Object)null)
					{
						return item;
					}
				}
			}
			return null;
		}

		private static bool Named(GameObject prefab, bool sound)
		{
			string text = ((Object)prefab).name.ToLowerInvariant();
			if (!sound)
			{
				if (!text.StartsWith("fx_"))
				{
					return text.StartsWith("vfx_");
				}
				return true;
			}
			return text.StartsWith("sfx_");
		}

		private static GameObject? Fits(GameObject? prefab, bool sound)
		{
			if (!sound)
			{
				return Usable(prefab);
			}
			return Audible(prefab);
		}

		private static GameObject? Usable(GameObject? prefab)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				return null;
			}
			if (!((Object)(object)prefab.GetComponentInChildren<ParticleSystem>(true) != (Object)null) && !((Object)(object)prefab.GetComponentInChildren<Renderer>(true) != (Object)null))
			{
				return null;
			}
			return prefab;
		}

		private static GameObject? Audible(GameObject? prefab)
		{
			if (!((Object)(object)prefab != (Object)null) || !((Object)(object)prefab.GetComponentInChildren<ZSFX>(true) != (Object)null))
			{
				return null;
			}
			return prefab;
		}
	}
	public sealed class LingeringVisual : MonoBehaviour
	{
		private const float BaselineRadius = 4f;

		private const float FadeSeconds = 1f;

		private ParticleSystem[] _systems = Array.Empty<ParticleSystem>();

		private Light[] _lights = Array.Empty<Light>();

		private AudioSource[] _audio = Array.Empty<AudioSource>();

		private float[] _lightBase = Array.Empty<float>();

		private float[] _audioBase = Array.Empty<float>();

		private float _life;

		private float _age;

		private bool _fading;

		public static void Attach(GameObject host, GameObject? prefab, float life, float radius)
		{
			LingeringVisual visual = host.AddComponent<LingeringVisual>();
			visual._life = Mathf.Max(life, 0.01f);
			Guard.Run("LingeringVisual.Build", delegate
			{
				visual.Build(host, prefab, radius);
			});
		}

		public static void Hold(GameObject host, GameObject? prefab, float radius)
		{
			Attach(host, prefab, float.PositiveInfinity, radius);
		}

		private void Build(GameObject host, GameObject? prefab, float radius)
		{
			//IL_000d: 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_0047: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = CosmeticClone.Spawn(prefab, host.transform, host.transform.position, endless: true);
			if ((Object)(object)val == (Object)null)
			{
				((Behaviour)this).enabled = false;
				return;
			}
			Transform transform = val.transform;
			transform.localScale *= Mathf.Max(radius, 0.01f) / 4f;
			Loop(val);
			Capture(val);
		}

		private void Loop(GameObject clone)
		{
			//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)
			_systems = clone.GetComponentsInChildren<ParticleSystem>(true);
			ParticleSystem[] systems = _systems;
			foreach (ParticleSystem obj in systems)
			{
				MainModule main = obj.main;
				((MainModule)(ref main)).loop = true;
				obj.Play(true);
			}
		}

		private void Capture(GameObject clone)
		{
			_lights = clone.GetComponentsInChildren<Light>(true);
			_audio = clone.GetComponentsInChildren<AudioSource>(true);
			_lightBase = Baseline(_lights, (Light l) => l.intensity);
			_audioBase = Baseline(_audio, (AudioSource a) => a.volume);
		}

		private static float[] Baseline<T>(T[] items, Func<T, float> read)
		{
			float[] array = new float[items.Length];
			for (int i = 0; i < items.Length; i++)
			{
				array[i] = read(items[i]);
			}
			return array;
		}

		private void Update()
		{
			Guard.Run("LingeringVisual.Update", delegate(LingeringVisual self)
			{
				self.Step();
			}, this);
		}

		private void Step()
		{
			_age += Time.deltaTime;
			if (!_fading && _age >= _life - 1f)
			{
				BeginFade();
			}
			if (_fading)
			{
				Dim(Mathf.Clamp01((_life - _age) / 1f));
			}
		}

		private void BeginFade()
		{
			//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)
			_fading = true;
			ParticleSystem[] systems = _systems;
			for (int i = 0; i < systems.Length; i++)
			{
				EmissionModule emission = systems[i].emission;
				((EmissionModule)(ref emission)).enabled = false;
			}
		}

		private void Dim(float factor)
		{
			for (int i = 0; i < _lights.Length; i++)
			{
				if ((Object)(object)_lights[i] != (Object)null)
				{
					_lights[i].intensity = _lightBase[i] * factor;
				}
			}
			for (int j = 0; j < _audio.Length; j++)
			{
				if ((Object)(object)_audio[j] != (Object)null)
				{
					_audio[j].volume = _audioBase[j] * factor;
				}
			}
		}
	}
	internal static class StarCorpse
	{
		public static void Made(Character creature, Ragdoll ragdoll)
		{
			int num = StarLook.StarsOf(creature);
			ZNetView component = ((Component)ragdoll).GetComponent<ZNetView>();
			if (num > 0 && !((Object)(object)component == (Object)null) && component.IsValid())
			{
				component.GetZDO().Set("ecr_corpse_stars", num);
				Show(ragdoll, num);
			}
		}

		public static void Wake(Ragdoll ragdoll)
		{
			ZNetView component = ((Component)ragdoll).GetComponent<ZNetView>();
			int num = (((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO().GetInt("ecr_corpse_stars", 0) : 0);
			if (num > 0)
			{
				Show(ragdoll, num);
			}
		}

		private static void Show(Ragdoll ragdoll, int stars)
		{
			LevelEffects[] componentsInChildren = ((Component)ragdoll).GetComponentsInChildren<LevelEffects>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				StarLook.Show(componentsInChildren[i], stars);
			}
		}
	}
	public static class StarLook
	{
		public static void Apply(Character character, int stars)
		{
			LevelEffects[] componentsInChildren = ((Component)character).GetComponentsInChildren<LevelEffects>();
			foreach (LevelEffects obj in componentsInChildren)
			{
				obj.m_character = character;
				Show(obj, stars);
			}
		}

		public static void Show(LevelEffects effects, int stars)
		{
			//IL_0013: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			int num = LevelFor(effects, stars);
			if (num > 1)
			{
				Vector3 localScale = ((Component)effects).transform.localScale;
				effects.SetupLevelVisualization(num);
				((Component)effects).transform.localScale = localScale;
			}
		}

		public static LevelSetup? SetupFor(LevelEffects effects)
		{
			int num = LevelFor(effects, StarsOf(effects.m_character));
			if (num <= 1)
			{
				return null;
			}
			return effects.m_levelSetups[num - 2];
		}

		public static int StarsOf(Character? character)
		{
			EliteController eliteController = (((Object)(object)character != (Object)null) ? ((Component)character).GetComponent<EliteController>() : null);
			if (!((Object)(object)eliteController != (Object)null) || !eliteController.Ready)
			{
				return 0;
			}
			return eliteController.Traits.Stars;
		}

		private static int LevelFor(LevelEffects effects, int stars)
		{
			if (stars > 0)
			{
				return Mathf.Min(stars + 1, effects.m_levelSetups.Count + 1);
			}
			return 1;
		}
	}
}
namespace EliteCreaturesReborn.Util
{
	internal static class ColorParse
	{
		public static Color Hex(string text, Color fallback)
		{
			//IL_0019: 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)
			Color result = default(Color);
			if (!string.IsNullOrWhiteSpace(text) && ColorUtility.TryParseHtmlString(text.Trim(), ref result))
			{
				return result;
			}
			return fallback;
		}
	}
	internal static class Dice
	{
		public static bool Percent(float chancePercent)
		{
			if (chancePercent <= 0f)
			{
				return false;
			}
			return Random.Range(0f, 100f) <= chancePercent;
		}

		public static float Draw()
		{
			return Random.Range(0f, 100f);
		}

		public static int Round(float amount)
		{
			int num = Mathf.FloorToInt(amount);
			if (!(Random.value < amount - (float)num))
			{
				return num;
			}
			return num + 1;
		}
	}
	internal static class Log
	{
		private static ManualLogSource? _log;

		public static bool Diagnostics;

		public static void Bind(ManualLogSource log)
		{
			_log = log;
		}

		public static void Info(string message)
		{
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogInfo((object)message);
			}
		}

		public static void Debug(string message)
		{
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogDebug((object)message);
			}
		}

		public static void Warn(string message)
		{
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogWarning((object)message);
			}
		}

		public static void Error(string message)
		{
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogError((object)message);
			}
		}

		public static void Diag(string message)
		{
			if (Diagnostics)
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)("[diag] " + message));
				}
			}
		}
	}
	internal static class Machine
	{
		public static bool Headless
		{
			get
			{
				if ((Object)(object)ZNet.instance != (Object)null)
				{
					return ZNet.instance.IsDedicated();
				}
				return false;
			}
		}
	}
	public static class NetTime
	{
		public static long NowMs()
		{
			if (!((Object)(object)ZNet.instance != (Object)null))
			{
				return 0L;
			}
			return (long)(ZNet.instance.GetTimeSeconds() * 1000.0);
		}

		public static float SecondsSince(long stampMs)
		{
			return (float)(NowMs() - stampMs) / 1000f;
		}

		public static double DaySeconds()
		{
			if (!((Object)(object)EnvMan.instance != (Object)null))
			{
				return 1800.0;
			}
			return EnvMan.instance.m_dayLengthSec;
		}
	}
}
namespace EliteCreaturesReborn.Traits
{
	public enum Aspect
	{
		None,
		Reflective,
		Shielded,
		Mending,
		Summoner,
		Elementalist,
		Enraged,
		Twin,
		Phantom,
		Adaptive,
		Fixated,
		Stormbound,
		Gravitic,
		Colossal,
		Tethered,
		Bountiful,
		Portalbound,
		Nightfall,
		Brutal,
		Echoing
	}
	public static class AspectCatalog
	{
		public static readonly Aspect[] InOrder = new Aspect[19]
		{
			Aspect.Reflective,
			Aspect.Shielded,
			Aspect.Mending,
			Aspect.Summoner,
			Aspect.Elementalist,
			Aspect.Enraged,
			Aspect.Twin,
			Aspect.Phantom,
			Aspect.Adaptive,
			Aspect.Fixated,
			Aspect.Stormbound,
			Aspect.Gravitic,
			Aspect.Colossal,
			Aspect.Tethered,
			Aspect.Bountiful,
			Aspect.Portalbound,
			Aspect.Nightfall,
			Aspect.Brutal,
			Aspect.Echoing
		};

		public static readonly Aspect[] Outcomes = new Aspect[20]
		{
			Aspect.None,
			Aspect.Reflective,
			Aspect.Shielded,
			Aspect.Mending,
			Aspect.Summoner,
			Aspect.Elementalist,
			Aspect.Enraged,
			Aspect.Twin,
			Aspect.Phantom,
			Aspect.Adaptive,
			Aspect.Fixated,
			Aspect.Stormbound,
			Aspect.Gravitic,
			Aspect.Colossal,
			Aspect.Tethered,
			Aspect.Bountiful,
			Aspect.Portalbound,
			Aspect.Nightfall,
			Aspect.Brutal,
			Aspect.Echoing
		};

		public static string Word(Aspect aspect)
		{
			if (aspect != Aspect.None)
			{
				return aspect.ToString();
			}
			return "";
		}

		public static string Name(Aspect aspect)
		{
			if (aspect != Aspect.None)
			{
				return Lang.Get("ecr_aspect_" + aspect.ToString().ToLowerInvariant());
			}
			return "";
		}

		public static string Key(Aspect aspect)
		{
			if (aspect != Aspect.None)
			{
				return aspect.ToString();
			}
			return "none";
		}

		public static Aspect? FromName(string name)
		{
			Aspect[] outcomes = Outcomes;
			foreach (Aspect aspect in outcomes)
			{
				if (string.Equals(Key(aspect), name, StringComparison.OrdinalIgnoreCase))
				{
					return aspect;
				}
			}
			return null;
		}
	}
	public static class AspectRoller
	{
		private const int BodyMask = 16768;

		public static Aspect Roll(string bossPrefab, Aspect? exclude)
		{
			AspectRules aspects = RuleState.Active.Boss.Aspects;
			if (!aspects.Enabled)
			{
				return Aspect.None;
			}
			List<KeyValuePair<Aspect, float>> list = Pool(aspects, bossPrefab, exclude);
			if (list.Count != 0)
			{
				return Pick(list);
			}
			return exclude.GetValueOrDefault();
		}

		public static List<Aspect> Choices(string bossPrefab)
		{
			AspectRules aspects = RuleState.Active.Boss.Aspects;
			if (!aspects.Enabled)
			{
				return new List<Aspect>();
			}
			return Pool(aspects, bossPrefab, null).ConvertAll((KeyValuePair<Aspect, float> entry) => entry.Key);
		}

		public static BossAspects RollBoss(string bossPrefab, Aspect? exclude)
		{
			Aspect num = Roll(bossPrefab, exclude);
			return new BossAspects(num, (num == Aspect.Bountiful) ? RollExtras(bossPrefab) : 0);
		}

		public static int RollExtras(string bossPrefab, int keep = 0)
		{
			List<KeyValuePair<Aspect, float>> list = ExtrasPool(RuleState.Active.Boss.Aspects, bossPrefab);
			list.RemoveAll((KeyValuePair<Aspect, float> entry) => !Fits(keep, entry.Key));
			int num = keep;
			for (int num2 = Count(keep); num2 < ExtraCount(); num2++)
			{
				if (list.Count <= 0)
				{
					break;
				}
				Aspect drawn = Pick(list);
				num |= 1 << (int)drawn;
				list.RemoveAll((KeyValuePair<Aspect, float> entry) => entry.Key == drawn || (BringsBodies(drawn) && BringsBodies(entry.Key)));
			}
			return num;
		}

		public static int ExtraCount()
		{
			return Mathf.Max(0, Mathf.RoundToInt(RuleState.Active.Boss.Aspects.PowerOf(Aspect.Bountiful, "extra aspects")));
		}

		public static List<Aspect> ExtraChoices(string bossPrefab)
		{
			AspectRules aspects = RuleState.Active.Boss.Aspects;
			if (!aspects.Enabled)
			{
				return new List<Aspect>();
			}
			return ExtrasPool(aspects, bossPrefab).ConvertAll((KeyValuePair<Aspect, float> entry) => entry.Key);
		}

		public static bool CanFill(string bossPrefab, int keep)
		{
			if (Count(keep) < ExtraCount())
			{
				return ExtraChoices(bossPrefab).Exists((Aspect aspect) => Fits(keep, aspect));
			}
			return false;
		}

		public static bool Fits(int mask, Aspect aspect)
		{
			if ((mask & (1 << (int)aspect)) == 0)
			{
				if (BringsBodies(aspect))
				{
					return !HoldsBodies(mask);
				}
				return true;
			}
			return false;
		}

		public static int Count(int mask)
		{
			int num = 0;
			for (int num2 = mask; num2 != 0; num2 &= num2 - 1)
			{
				num++;
			}
			return num;
		}

		public static bool BringsBodies(Aspect aspect)
		{
			return (0x4180 & (1 << (int)aspect)) != 0;
		}

		public static bool HoldsBodies(int mask)
		{
			return (0x4180 & mask) != 0;
		}

		private static List<KeyValuePair<Aspect, float>> ExtrasPool(AspectRules rules, string bossPrefab)
		{
			List<KeyValuePair<Aspect, float>> list = Pool(rules, bossPrefab, Aspect.None);
			list.RemoveAll((KeyValuePair<Aspect, float> entry) => entry.Key == Aspect.Bountiful);
			if (list.Count == 0 && Registrations.AspectsOf(bossPrefab) != null)
			{
				list = RulePool(rules, bossPrefab, Aspect.None);
				list.RemoveAll((KeyValuePair<Aspect, float> entry) => entry.Key == Aspect.Bountiful);
			}
			return list;
		}

		private static List<KeyValuePair<Aspect, float>> Pool(AspectRules rules, string bossPrefab, Aspect? exclude)
		{
			Aspect[] array = Registrations.AspectsOf(bossPrefab);
			if (array == null)
			{
				return RulePool(rules, bossPrefab, exclude);
			}
			return OwnPool(rules, array, exclude);
		}

		private static List<KeyValuePair<Aspect, float>> OwnPool(AspectRules rules, Aspect[] own, Aspect? exclude)
		{
			List<KeyValuePair<Aspect, float>> list = new List<KeyValuePair<Aspect, float>>();
			foreach (Aspect aspect in own)
			{
				if (aspect != exclude)
				{
					list.Add(new KeyValuePair<Aspect, float>(aspect, rules.ChanceOf(aspect)));
				}
			}
			if (list.Exists((KeyValuePair<Aspect, float> entry) => entry.Value > 0f))
			{
				list.RemoveAll((KeyValuePair<Aspect, float> entry) => entry.Value <= 0f);
				return list;
			}
			return list.ConvertAll((KeyValuePair<Aspect, float> entry) => new KeyValuePair<Aspect, float>(entry.Key, 1f));
		}

		private static List<KeyValuePair<Aspect, float>> RulePool(AspectRules rules, string bossPrefab, Aspect? exclude)
		{
			List<KeyValuePair<Aspect, float>> list = new List<KeyValuePair<Aspect, float>>();
			Aspect[] outcomes = AspectCatalog.Outcomes;
			foreach (Aspect aspect in outcomes)
			{
				float num = rules.ChanceOf(aspect);
				if (aspect != exclude && num > 0f && rules.InRotation(bossPrefab, aspect))
				{
					list.Add(new KeyValuePair<Aspect, float>(aspect, num));
				}
			}
			return list;
		}

		private static Aspect Pick(List<KeyValuePair<Aspect, float>> pool)
		{
			float num = 0f;
			foreach (KeyValuePair<Aspect, float> item in pool)
			{
				num += item.Value;
			}
			float num2 = Random.Range(0f, num);
			foreach (KeyValuePair<Aspect, float> item2 in pool)
			{
				num2 -= item2.Value;
				if (num2 < 0f)
				{
					return item2.Key;
				}
			}
			return pool[pool.Count - 1].Key;
		}
	}
	public static class AspectStore
	{
		private static readonly int AltarAspectHash = StringExtensionMethods.GetStableHashCode("ecr_altar_aspect");

		private static readonly int AltarExtraHash = StringExtensionMethods.GetStableHashCode("ecr_altar_extra");

		private static readonly int AltarShiftAtHash = StringExtensionMethods.GetStableHashCode("ecr_altar_shift");

		private static readonly int AltarStarsHash = StringExtensionMethods.GetStableHashCode("ecr_altar_stars");

		private static readonly int AltarPickStarsHash = StringExtensionMethods.GetStableHashCode("ecr_altar_pick_stars");

		private static readonly int AltarPickAspectHash = StringExtensionMethods.GetStableHashCode("ecr_altar_pick_aspect");

		private static readonly int AltarPickExtrasHash = StringExtensionMethods.GetStableHashCode("ecr_altar_pick_extras");

		private static readonly int SummonWavesHash = StringExtensionMethods.GetStableHashCode("ecr_waves");

		private static readonly int PhantomOrderHash = StringExtensionMethods.GetStableHashCode("ecr_phantom_order");

		private static readonly int PhantomSplitsHash = StringExtensionMethods.GetStableHashCode("ecr_phantom_splits");

		private static readonly KeyValuePair<int, int> TwinPartnerKey = ZDO.GetHashZDOID("ecr_twin");

		private static readonly KeyValuePair<int, int> TetherPartnerKey = ZDO.GetHashZDOID("ecr_tether");

		private static readonly KeyValuePair<int, int> PhantomOfKey = ZDO.GetHashZDOID("ecr_phantom_of");

		private static readonly KeyValuePair<int, int> EchoOfKey = ZDO.GetHashZDOID("ecr_echo_of");

		private const int Unrolled = -1;

		public static bool AltarRolled(ZDO zdo)
		{
			return zdo.GetInt(AltarAspectHash, -1) != -1;
		}

		public static Aspect GetAltarAspect(ZDO zdo)
		{
			int num = zdo.GetInt(AltarAspectHash, -1);
			if (num != -1)
			{
				return (Aspect)num;
			}
			return Aspect.None;
		}

		public static BossAspects GetAltarAspects(ZDO zdo)
		{
			return new BossAspects(GetAltarAspect(zdo), zdo.GetInt(AltarExtraHash, 0));
		}

		public static long GetAltarShiftAt(ZDO zdo)
		{
			return zdo.GetLong(AltarShiftAtHash, 0L);
		}

		public static void SetAltarAspects(ZDO zdo, BossAspects aspects)
		{
			zdo.Set("ecr_altar_aspect", (int)aspects.Headline);
			if (zdo.GetInt(AltarExtraHash, 0) != aspects.Extras)
			{
				zdo.Set("ecr_altar_extra", aspects.Extras);
			}
		}

		public static void SetAltarShiftAt(ZDO zdo, long shiftAtMs)
		{
			zdo.Set("ecr_altar_shift", shiftAtMs);
		}

		public static bool AltarStarsRolled(ZDO zdo)
		{
			return zdo.GetInt(AltarStarsHash, -1) != -1;
		}

		public static int GetAltarStars(ZDO zdo)
		{
			int num = zdo.GetInt(AltarStarsHash, -1);
			if (num >= 0)
			{
				return num;
			}
			return 0;
		}

		public static void SetAltarStars(ZDO zdo, int stars)
		{
			zdo.Set("ecr_altar_stars", stars);
		}

		public static int GetPickedStars(ZDO zdo)
		{
			return zdo.GetInt(AltarPickStarsHash, -1);
		}

		public static int GetPickedAspect(ZDO zdo)
		{
			return zdo.GetInt(AltarPickAspectHash, -1);
		}

		public static void SetPicks(ZDO zdo, int stars, int aspect)
		{
			zdo.Set("ecr_altar_pick_stars", stars);
			zdo.Set("ecr_altar_pick_aspect", aspect);
		}

		public static int GetPickedExtras(ZDO zdo)
		{
			return zdo.GetInt(AltarPickExtrasHash, 0);
		}

		public static void SetPickedExtras(ZDO zdo, int extras)
		{
			if (zdo.GetInt(AltarPickExtrasHash, 0) != extras)
			{
				zdo.Set("ecr_altar_pick_extras", extras);
			}
		}

		public static ZDOID GetTwin(ZDO zdo)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return zdo.GetZDOID(TwinPartnerKey);
		}

		public static void SetTwin(ZDO zdo, ZDOID partner)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			zdo.Set("ecr_twin", partner);
		}

		public static ZDOID GetTether(ZDO zdo)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return zdo.GetZDOID(TetherPartnerKey);
		}

		public static void SetTether(ZDO zdo, ZDOID partner)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			zdo.Set("ecr_tether", partner);
		}

		public static ZDOID GetPhantomOf(ZDO zdo)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return zdo.GetZDOID(PhantomOfKey);
		}

		public static void SetPhantomOf(ZDO zdo, ZDOID boss)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			zdo.Set("ecr_phantom_of", boss);
		}

		public static ZDOID GetEchoOf(ZDO zdo)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return zdo.GetZDOID(EchoOfKey);
		}

		public static void SetEchoOf(ZDO zdo, ZDOID boss)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			zdo.Set("ecr_echo_of", boss);
		}

		public static int GetWaves(ZDO zdo)
		{
			return zdo.GetInt(SummonWavesHash, 0);
		}

		public static void SetWaves(ZDO zdo, int waves)
		{
			zdo.Set("ecr_waves", waves);
		}

		public static float GetPhantomOrder(ZDO zdo)
		{
			return zdo.GetFloat(PhantomOrderHash, 0f);
		}

		public static void SetPhantomOrder(ZDO zdo, float order)
		{
			zdo.Set("ecr_phantom_order", order);
		}

		public static int GetSplits(ZDO zdo)
		{
			return zdo.GetInt(PhantomSplitsHash, 0);
		}

		public static void SetSplits(ZDO zdo, int splits)
		{
			zdo.Set("ecr_phantom_splits", splits);
		}
	}
	public static class BodySize
	{
		public const int LargeBars = 5120;

		private const float LargeRadius = 1f;

		private const float LargeLength = 3.5f;

		private const float MinHealth = 300f;

		private const float Slack = 0.01f;

		private static readonly Dictionary<int, bool> Verdicts = new Dictionary<int, bool>();

		public static bool IsLarge(Character creature)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			int num = PrefabHash(creature);
			if (Verdicts.TryGetValue(num, out var value))
			{
				return value;
			}
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(num) : null);
			if (!((Object)(object)val != (Object)null))
			{
				return Measure(((Component)creature).gameObject, Vector3.one);
			}
			return Verdict(num, val);
		}

		public static int Barred(Character creature)
		{
			if (!IsLarge(creature) && !GrowsLarge(((Component)creature).GetComponent<Growup>()))
			{
				return 0;
			}
			return 5120;
		}

		private static bool GrowsLarge(Growup? young)
		{
			if ((Object)(object)young == (Object)null)
			{
				return false;
			}
			bool flag = IsLargePrefab(young.m_grownPrefab);
			foreach (GrownEntry item in young.m_altGrownPrefabs ?? new List<GrownEntry>())
			{
				flag |= IsLargePrefab(item.m_prefab);
			}
			return flag;
		}

		private static bool IsLargePrefab(GameObject? prefab)
		{
			if ((Object)(object)prefab != (Object)null)
			{
				return Verdict(StringExtensionMethods.GetStableHashCode(((Object)prefab).name), prefab);
			}
			return false;
		}

		private static bool Verdict(int hash, GameObject prefab)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (!Verdicts.TryGetValue(hash, out var value))
			{
				value = Measure(prefab, prefab.transform.localScale);
				Verdicts[hash] = value;
			}
			return value;
		}

		private static bool Measure(GameObject body, Vector3 scale)
		{
			CapsuleCollider component = body.GetComponent<CapsuleCollider>();
			Character component2 = body.GetComponent<Character>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || component2.m_health < 300f)
			{
				return false;
			}
			int num = Mathf.Clamp(component.direction, 0, 2);
			float num2 = Mathf.Abs(((Vector3)(ref scale))[num]);
			float num3 = Mathf.Max(Mathf.Abs(((Vector3)(ref scale))[(num + 1) % 3]), Mathf.Abs(((Vector3)(ref scale))[(num + 2) % 3]));
			if (!(component.radius * num3 >= 0.99f))
			{
				return component.height * num2 >= 3.49f;
			}
			return true;
		}

		private static int PrefabHash(Character creature)
		{
			ZNetView nview = creature.m_nview;
			ZDO val = (((Object)(object)nview != (Object)null && nview.IsValid()) ? nview.GetZDO() : null);
			if (val == null)
			{
				return StringExtensionMethods.GetStableHashCode(Utils.GetPrefabName(((Component)creature).gameObject));
			}
			return val.GetPrefab();
		}
	}
	public readonly struct BossAspects
	{
		public static readonly BossAspects None = new BossAspects(Aspect.None, 0);

		public readonly Aspect Headline;

		public readonly int Extras;

		public BossAspects(Aspect headline, int extras)
		{
			Headline = headline;
			Extras = extras;
		}

		public CreatureTraits ToTraits(int stars)
		{
			return new CreatureTraits(stars, Headline)
			{
				ExtraAspects = Extras
			};
		}

		public IEnumerable<Aspect> ExtrasInOrder()
		{
			Aspect[] inOrder = AspectCatalog.InOrder;
			foreach (Aspect aspect in inOrder)
			{
				if (aspect != Headline && (Extras & (1 << (int)aspect)) != 0)
				{
					yield return aspect;
				}
			}
		}
	}
	public readonly struct BossDraw
	{
		public readonly int Stars;

		public readonly BossAspects Aspects;

		public BossDraw(int stars, BossAspects aspects)
		{
			Stars = stars;
			Aspects = aspects;
		}

		public CreatureTraits ToTraits()
		{
			return Aspects.ToTraits(Stars);
		}

		public static BossDraw Roll(string bossPrefab, float starBoost)
		{
			return new BossDraw(RollStars(starBoost), AspectRoller.RollBoss(bossPrefab, null));
		}

		public static int RollStars(float starBoost)
		{
			BossRules boss = RuleState.Active.Boss;
			if (!boss.Enabled)
			{
				return 0;
			}
			return TraitRoller.RollStars(BossView.For(boss), starBoost);
		}
	}
	public sealed class CreatureTraits
	{
		public int Stars;

		public int Mask;

		public Aspect Aspect;

		public int ExtraAspects;

		public bool PhantomCopy;

		public bool Echo;

		public bool Decoy;

		public int Tier;

		public bool GameStars;

		public bool Any => Mask != 0;

		public bool AnyAspect
		{
			get
			{
				if (Aspect == Aspect.None)
				{
					return ExtraAspects != 0;
				}
				return true;
			}
		}

		public int LargeGlyphs => Stars / 5;

		public int Count
		{
			get
			{
				int num = 0;
				foreach (Mutation item in Active())
				{
					_ = item;
					num++;
				}
				return num;
			}
		}

		public CreatureTraits(int stars, int mask)
		{
			Stars = stars;
			Mask = mask;
		}

		public CreatureTraits(int stars, Aspect aspect)
		{
			Stars = stars;
			Aspect = aspect;
		}

		public bool Has(Mutation mutation)
		{
			if (!Decoy && !PhantomCopy)
			{
				return Wears(mutation);
			}
			return false;
		}

		public bool Wears(Mutation mutation)
		{
			return (Mask & (1 << (int)mutation)) != 0;
		}

		public void Add(Mutation mutation)
		{
			Mask |= 1 << (int)mutation;
		}

		public void Remove(Mutation mutation)
		{
			Mask &= ~(1 << (int)mutation);
		}

		public bool HasAspect(Aspect aspect)
		{
			if (aspect != Aspect.None)
			{
				if (Aspect != aspect)
				{
					return (ExtraAspects & (1 << (int)aspect)) != 0;
				}
				return true;
			}
			return false;
		}

		public IEnumerable<Aspect> Aspects()
		{
			if (Aspect != Aspect.None)
			{
				yield return Aspect;
			}
			Aspect[] inOrder = AspectCatalog.InOrder;
			foreach (Aspect aspect in inOrder)
			{
				if (aspect != Aspect && (ExtraAspects & (1 << (int)aspect)) != 0)
				{
					yield return aspect;
				}
			}
		}

		public bool OnLargeStar(Mutation mutation)
		{
			if (!Wears(mutation))
			{
				return false;
			}
			int num = 0;
			foreach (Mutation item in Active())
			{
				if (item == mutation)
				{
					return num < LargeGlyphs;
				}
				num++;
			}
			return false;
		}

		public IEnumerable<Mutation> Active()
		{
			Mutation[] inOrder = MutationCatalog.InOrder;
			foreach (Mutation mutation in inOrder)
			{
				if (Wears(mutation))
				{
					yield return mutation;
				}
			}
		}
	}
	public static class DeathBrood
	{
		public const int Bars = 8;

		private static readonly Dictionary<string, bool> Verdicts = new Dictionary<string, bool>(StringComparer.Ordinal);

		public static int BarsOf(string prefab)
		{
			if (!Releases(prefab))
			{
				return 0;
			}
			return 8;
		}

		public static bool Releases(string prefab)
		{
			if (Verdicts.TryGetValue(prefab, out var value))
			{
				return value;
			}
			GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(prefab) : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			value = Read(val);
			Verdicts[prefab] = value;
			return value;
		}

		private static bool Read(GameObject body)
		{
			Character component = body.GetComponent<Character>();
			CharacterDrop component2 = body.GetComponent<CharacterDrop>();
			if (!((Object)(object)component != (Object)null) || !InEffects(component.m_deathEffects, ragdolls: true))
			{
				if ((Object)(object)component2 != (Object)null)
				{
					return InDrops(component2.m_drops);
				}
				return false;
			}
			return true;
		}

		private static bool InEffects(EffectList? effects, bool ragdolls)
		{
			EffectData[] array = effects?.m_effectPrefabs ?? Array.Empty<EffectData>();
			foreach (EffectData val in array)
			{
				GameObject val2 = ((val != null && val.m_enabled) ? val.m_prefab : null);
				if (!((Object)(object)val2 == (Object)null))
				{
					Ragdoll val3 = (ragdolls ? val2.GetComponent<Ragdoll>() : null);
					if ((Object)(object)val2.GetComponent<Character>() != (Object)null || ((Object)(object)val3 != (Object)null && InEffects(val3.m_removeEffect, ragdolls: false)))
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool InDrops(List<Drop>? drops)
		{
			foreach (Drop item in drops ?? new List<Drop>())
			{
				if ((Object)(object)item?.m_prefab != (Object)null && (Object)(object)item.m_prefab.GetComponent<Character>() != (Object)null)
				{
					return true;
				}
			}
			return false;
		}
	}
	public enum Mutation
	{
		Mad,
		Bloated,
		Cloaked,
		Splintering,
		Leeching,
		Warding,
		Plated,
		Miasmic,
		Devouring,
		Thieving,
		Gilded,
		Blinking,
		Relentless,
		Juggernaut,
		Screecher,
		Frostbound,
		Mudbound,
		Corrodent,
		Cloning,
		Piercing,
		Howling,
		Binding,
		Flamebound
	}
	public static class MutationBars
	{
		private static readonly Dictionary<string, int> KindBars = new Dictionary<string, int> { ["Deathsquito"] = 4 };

		public static int Of(Character creature)
		{
			return BodySize.Barred(creature) | OfKind(Utils.GetPrefabName(((Component)creature).gameObject));
		}

		public static int OfKind(string prefab)
		{
			int value;
			return (KindBars.TryGetValue(prefab, out value) ? value : 0) | DeathBrood.BarsOf(prefab);
		}
	}
	public static class MutationCatalog
	{
		public static readonly Mutation[] InOrder = new Mutation[23]
		{
			Mutation.Mad,
			Mutation.Bloated,
			Mutation.Cloaked,
			Mutation.Splintering,
			Mutation.Leeching,
			Mutation.Warding,
			Mutation.Plated,
			Mutation.Miasmic,
			Mutation.Devouring,
			Mutation.Thieving,
			Mutation.Gilded,
			Mutation.Blinking,
			Mutation.Relentless,
			Mutation.Juggernaut,
			Mutation.Screecher,
			Mutation.Frostbound,
			Mutation.Mudbound,
			Mutation.Corrodent,
			Mutation.Cloning,
			Mutation.Piercing,
			Mutation.Howling,
			Mutation.Binding,
			Mutation.Flamebound
		};

		public static bool OnByDefault(Mutation mutation)
		{
			if (mutation != Mutation.Piercing && mutation != Mutation.Howling)
			{
				return mutation != Mutation.Binding;
			}
			return false;
		}

		public static Mutation? FromName(string name)
		{
			Mutation[] inOrder = InOrder;
			foreach (Mutation mutation in inOrder)
			{
				if (string.Equals(Word(mutation), name, StringComparison.OrdinalIgnoreCase))
				{
					return mutation;
				}
			}
			return null;
		}

		public static string Name(Mutation mutation)
		{
			return Lang.Get(NameKey(mutation));
		}

		public static string NameKey(Mutation mutation)
		{
			return "ecr_mut_" + mutation.ToString().ToLowerInvariant();
		}

		public static string Word(Mutation mutation)
		{
			return mutation switch
			{
				Mutation.Mad => "Mad", 
				Mutation.Bloated => "Bloated", 
				Mutation.Cloaked => "Cloaked", 
				Mutation.Splintering => "Splintering", 
				Mutation.Leeching => "Leeching", 
				Mutation.Warding => "Warding", 
				Mutation.Plated => "Plated", 
				Mutation.Miasmic => "Miasmic", 
				Mutation.Devouring => "Devouring", 
				Mutation.Thieving => "Thieving", 
				Mutation.Gilded => "Gilded", 
				Mutation.Blinking => "Blinking", 
				Mutation.Relentless => "Relentless", 
				Mutation.Juggernaut => "Juggernaut", 
				Mutation.Screecher => "Screecher", 
				Mutation.Frostbound => "Frostbound", 
				Mutation.Mudbound => "Mudbound", 
				Mutation.Corrodent => "Corrodent", 
				Mutation.Cloning => "Cloning", 
				Mutation.Piercing => "Piercing", 
				Mutation.Howling => "Howling", 
				Mutation.Binding => "Binding", 
				Mutation.Flamebound => "Flamebound", 
				_ => "", 
			};
		}

		public static string DefaultColorHex(Mutation mutation)
		{
			return mutation switch
			{
				Mutation.Mad => "#E23030", 
				Mutation.Bloated => "#8B5A2B", 
				Mutation.Cloaked => "#4AA6FF", 
				Mutation.Splintering => "#FFFFFF", 
				Mutation.Leeching => "#33CC33", 
				Mutation.Warding => "#101C50", 
				Mutation.Plated => "#F2C40C", 
				Mutation.Miasmic => "#1E6B2E", 
				Mutation.Devouring => "#7A0F0F", 
				Mutation.Thieving => "#A64BE0", 
				Mutation.Gilded => "#FFE066", 
				Mutation.Blinking => "#29E0E0", 
				Mutation.Relentless => "#FF7F24", 
				Mutation.Juggernaut => "#6E6E6E", 
				Mutation.Screecher => "#FF5CC8", 
				Mutation.Frostbound => "#BFEFFF", 
				Mutation.Mudbound => "#5E4A1E", 
				Mutation.Corrodent => "#B7410E", 
				Mutation.Cloning => "#B4A8FF", 
				Mutation.Piercing => "#C2185B", 
				Mutation.Howling => "#2E8B8B", 
				Mutation.Binding => "#6B8E23", 
				Mutation.Flamebound => "#FF4500", 
				_ => "#FFFFFF", 
			};
		}
	}
	public static class PresetRoller
	{
		public static CreatureTraits Roll(BiomeRules rules, RuleSet ruleSet, int tier, Biome biome, int barred)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			PresetCell presetCell = PresetCell.For(ruleSet.Difficulty, tier, PresetTables.Rank(biome));
			int num = (ruleSet.CreatureStars ? TraitRoller.PickWeighted(presetCell.Weights) : 0);
			int mask = (Dice.Percent(Mathf.Min(100f, presetCell.Mutation * (1f + 0.25f * (float)num))) ? PickOne(rules, ruleSet, num, barred) : 0);
			return new CreatureTraits(num, mask)
			{
				Tier = tier
			};
		}

		private static int PickOne(BiomeRules rules, RuleSet ruleSet, int stars, int barred)
		{
			Mutation[] inOrder = MutationCatalog.InOrder;
			float[] array = new float[inOrder.Length];
			float num = 0f;
			for (int i = 0; i < inOrder.Length; i++)
			{
				array[i] = (TraitRoller.MayRoll(inOrder[i], ruleSet, barred) ? Mathf.Max(0f, rules.ChanceOf(inOrder[i], stars)) : 0f);
				num += array[i];
			}
			if (num <= 0f)
			{
				return 0;
			}
			return 1 << (int)inOrder[TraitRoller.PickWeighted(array)];
		}
	}
	public static class RegisteredMutations
	{
		private static readonly HashSet<string> Warned = new HashSet<string>(StringComparer.Ordinal);

		public static int For(Character creature, string prefab)
		{
			int num = Registrations.MutationsOf(prefab);
			if (num != 0)
			{
				return Allowed(num, prefab, RuleState.Active, BodySize.Barred(creature), MutationBars.OfKind(prefab));
			}
			return 0;
		}

		public static int Allowed(int mask, string prefab, RuleSet rules, int bodyBars, int kindBars)
		{
			Mutation[] inOrder = MutationCatalog.InOrder;
			foreach (Mutation mutation in inOrder)
			{
				string text = (((mask & Bit(mutation)) != 0) ? Refusal(mutation, rules, bodyBars, kindBars) : null);
				if (text != null)
				{
					mask &= ~Bit(mutation);
					WarnOnce(prefab, mutation, text);
				}
			}
			return mask;
		}

		public static string? Refusal(Mutation mutation, RuleSet rules, int bodyBars, int kindBars)
		{
			if ((kindBars & Bit(mutation)) != 0)
			{
				return "its kind never carries it";
			}
			if ((bodyBars & Bit(mutation)) != 0)
			{
				return "its body is large: no Gilded or Relentless on large creatures";
			}
			if (!rules.IsEnabled(mutation))
			{
				return "it is switched off in the .cfg (2 - Mutations)";
			}
			return null;
		}

		private static int Bit(Mutation mutation)
		{
			return 1 << (int)mutation;
		}

		private static void WarnOnce(string prefab, Mutation mutation, string why)
		{
			string text = MutationCatalog.Word(mutation);
			if (Warned.Add(prefab + "|" + text))
			{
				Log.Warn(prefab + ": registered mutation '" + text + "' skipped - " + why);
			}
		}
	}
	public static class Registrations
	{
		private sealed class Entry
		{
			public int Mutations;

			public Aspect[]? Aspects;

			public string[]? PortalAttacks;

			public SummonPick[]? Summons;

			public bool Empty
			{
				get
				{
					if (Mutations == 0 && Aspects == null && PortalAttacks == null)
					{
						return Summons == null;
					}
					return false;
				}
			}
		}

		private static readonly Dictionary<string, Entry> ByPrefab = new Dictionary<string, Entry>(StringComparer.Ordinal);

		public static bool Has(string prefab)
		{
			return ByPrefab.ContainsKey(prefab);
		}

		public static int MutationsOf(string prefab)
		{
			return Find(prefab)?.Mutations ?? 0;
		}

		public static Aspect[]? AspectsOf(string prefab)
		{
			return Find(prefab)?.Aspects;
		}

		public static string[]? PortalAttacksOf(string prefab)
		{
			return Find(prefab)?.PortalAttacks;
		}

		public static SummonPick[]? SummonsOf(string prefab)
		{
			return Find(prefab)?.Summons;
		}

		public static void SetMutations(string prefab, int mask)
		{
			Change(prefab, delegate(Entry entry)
			{
				entry.Mutations = mask;
			});
		}

		public static void SetAspects(string prefab, Aspect[] aspects)
		{
			Change(prefab, delegate(Entry entry)
			{
				entry.Aspects = ((aspects.Length != 0) ? aspects : null);
			});
		}

		public static void SetPortalAttacks(string prefab, string[] attacks)
		{
			Change(prefab, delegate(Entry entry)
			{
				entry.PortalAttacks = ((attacks.Length != 0) ? attacks : null);
			});
		}

		public static void SetSummons(string prefab, SummonPick[] summons)
		{
			Change(prefab, delegate(Entry entry)
			{
				entry.Summons = ((summons.Length != 0) ? summons : null);
			});
		}

		public static void Clear(string prefab)
		{
			ByPrefab.Remove(prefab);
		}

		private static Entry? Find(string prefab)
		{
			if (prefab == null || !ByPrefab.TryGetValue(prefab, out Entry value))
			{
				return null;
			}
			return value;
		}

		private static void Change(string prefab, Action<Entry> change)
		{
			if (!ByPrefab.TryGetValue(prefab, out Entry value))
			{
				value = new Entry();
			}
			change(value);
			if (value.Empty)
			{
				ByPrefab.Remove(prefab);
			}
			else
			{
				ByPrefab[prefab] = value;
			}
		}
	}
	public static class SplinterTable
	{
		private static readonly float[][] Weights = new float[5][]
		{
			new float[5] { 0f, 0f, 0f, 0f, 100f },
			new float[5] { 15f, 0f, 0f, 0f, 85f },
			new float[5] { 15f, 35f, 0f, 0f, 50f },
			new float[5] { 15f, 35f, 30f, 0f, 20f },
			new float[5] { 15f, 35f, 30f, 15f, 5f }
		};

		public static int RollChildStars(int parentStars)
		{
			if (parentStars <= 0)
			{
				return 0;
			}
			float[] array = Weights[Mathf.Clamp(parentStars, 1, 5) - 1];
			float num = Dice.Draw();
			float num2 = 0f;
			for (int i = 0; i < 4; i++)
			{
				num2 += array[i];
				if (num <= num2)
				{
					return Mathf.Max(0, parentStars - (i + 1));
				}
			}
			return 0;
		}
	}
	public static class StarCap
	{
		public static int For(RuleSet set, BiomeRules rules, int tier, Biome biome)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (set.Difficulty != Difficulty.Custom)
			{
				return PresetCell.For(set.Difficulty, tier, PresetTables.Rank(biome)).Cap;
			}
			return rules.StarCeiling;
		}
	}
	public readonly struct SummonPick
	{
		public const int OwnStars = -1;

		public readonly string Prefab;

		public readonly int Stars;

		public SummonPick(string prefab, int stars)
		{
			Prefab = prefab;
			Stars = ((stars < 0) ? (-1) : stars);
		}

		public int StarsOr(int own)
		{
			if (Stars >= 0)
			{
				return Stars;
			}
			return own;
		}
	}
	public static class TraitKeys
	{
		public const string Resolved = "ecr_resolved";

		public const string Stars = "ecr_stars";

		public const string Mask = "ecr_mask";

		public const string Biome = "ecr_biome";

		public const string Tier = "ecr_tier";

		public const string SireStars = "ecr_sire_stars";

		public const string SireMask = "ecr_sire_mask";

		public const string EggTraits = "ecr_egg";

		public const string DevouredHealth = "ecr_dev_hp";

		public const string DevouredDamage = "ecr_dev_dmg";

		public const string Generation = "ecr_gen";

		public const string CascadeRoot = "ecr_root";

		public const string MiasmaTrail = "ecr_miasma";

		public const string MiasmaSeq = "ecr_miasma_seq";

		public const string DevourReadyAt = "ecr_dev_ready";

		public const string LootFilledAt = "ecr_loot_at";

		public const string DevouredBy = "ecr_devoured_by";

		public const string DevouredMeals = "ecr_dev_meals";

		public const string Pouch = "ecr_stolen";

		public const string Aspect = "ecr_aspect";

		public const string AspectExtra = "ecr_aspect_extra";

		public const string AltarExtra = "ecr_altar_extra";

		public const string AltarAspect = "ecr_altar_aspect";

		public const string AltarShiftAt = "ecr_altar_shift";

		public const string AltarStars = "ecr_altar_stars";

		public const string AltarPickStars = "ecr_altar_pick_stars";

		public const string AltarPickAspect = "ecr_altar_pick_aspect";

		public const string AltarPickExtras = "ecr_altar_pick_extras";

		public const string TwinPartner = "ecr_twin";

		public const string PhantomOf = "ecr_phantom_of";

		public const string PhantomSplits = "ecr_phantom_splits";

		public const string PhantomOrder = "ecr_phantom_order";

		public const string SummonWaves = "ecr_waves";

		public const string BossDamage = "ecr_boss_dmg";

		public const string Adapted = "ecr_adaptive";

		public const string Fixated = "ecr_fixated";

		public const string FixatedAt = "ecr_fixated_at";

		public const string BlinkedAt = "ecr_blink_at";

		public const string StormAt = "ecr_storm_at";

		public const string StormCircles = "ecr_storm";

		public const string Quarry = "ecr_quarry";

		public const string GravityAt = "ecr_gravity_at";

		public const string CorpseScale = "ecr_corpse_scale";

		public const string CorpseStars = "ecr_corpse_stars";

		public const string TetherPartner = "ecr_tether";

		public const string PortalAt = "ecr_portal_at";

		public const string PortalSpot = "ecr_portal_spot";

		public const string ShriekAt = "ecr_shriek_at";

		public const string FrostTrail = "ecr_frost_trail";

		public const string FrostTrailSeq = "ecr_frost_trail_seq";

		public const string MudTrail = "ecr_mud_trail";

		public const string MudTrailSeq = "ecr_mud_trail_seq";

		public const string FireTrail = "ecr_fire_trail";

		public const string FireTrailSeq = "ecr_fire_trail_seq";

		public const string BindTrail = "ecr_bind_trail";

		public const string BindTrailSeq = "ecr_bind_trail_seq";

		public const string HowlAt = "ecr_howl_at";

		public const string CloneDecoy = "ecr_clone_decoy";

		public const string CloneOf = "ecr_clone_of";

		public const string Clones = "ecr_clones";

		public const string CloneAt = "ecr_clone_at";

		public const string TornadoAt = "ecr_tornado_at";

		public const string TornadoWave = "ecr_tornado";

		public const string TornadoTrack = "ecr_tornado_track";

		public const string EchoOf = "ecr_echo_of";

		public const string TameStrip = "ecr_tame_strip";

		public const string TameStars = "ecr_tame_stars";

		public const string TameMask = "ecr_tame_mask";

		public const string GameLevel = "ecr_game_level";

		public const string LootLevel = "ecr_loot_level";
	}
	public static class TraitRoller
	{
		public static CreatureTraits Roll(BiomeRules rules, RuleSet ruleSet, int tier, Biome biome, int barred)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (ruleSet.Difficulty != Difficulty.Custom)
			{
				return PresetRoller.Roll(rules, ruleSet, tier, biome, barred);
			}
			int stars = (ruleSet.CreatureStars ? RollStars(rules.StarChances, ruleSet.Tiers.StarBoostAt(tier)) : 0);
			int mask = RollMutations(rules, stars, ruleSet, ruleSet.Tiers.MutationBoostAt(tier), barred);
			return new CreatureTraits(stars, mask)
			{
				Tier = tier
			};
		}

		internal static bool MayRoll(Mutation mutation, RuleSet ruleSet, int barred)
		{
			if (ruleSet.IsEnabled(mutation))
			{
				return (barred & (1 << (int)mutation)) == 0;
			}
			return false;
		}

		public static int RollStars(BiomeRules rules)
		{
			return RollStars(rules.StarChances, 1f);
		}

		public static int RollStars(BiomeRules rules, float boost)
		{
			return RollStars(rules.StarChances, boost);
		}

		private static int RollStars(float[] chances, float boost)
		{
			return PickWeighted(Boosted(chances, boost));
		}

		internal static int PickWeighted(float[] weights)
		{
			float num = 0f;
			foreach (float num2 in weights)
			{
				num += num2;
			}
			if (num <= 0f)
			{
				return 0;
			}
			return PickIndex(weights, Random.Range(0f, num));
		}

		private static float[] Boosted(float[] chances, float boost)
		{
			float[] array = new float[chances.Length];
			float num = 1f;
			for (int i = 0; i < chances.Length; i++)
			{
				array[i] = Mathf.Max(0f, chances[i]) * num;
				num *= Mathf.Max(0f, boost);
			}
			return array;
		}

		private static int PickIndex(float[] chances, float draw)
		{
			float num = 0f;
			for (int i = 0; i < chances.Length; i++)
			{
				num += Mathf.Max(0f, chances[i]);
				if (draw < num)
				{
					return i;
				}
			}
			return chances.Length - 1;
		}

		private static int RollMutations(BiomeRules rules, int stars, RuleSet ruleSet, float boost, int barred)
		{
			List<Mutation> list = new List<Mutation>();
			Mutation[] inOrder = MutationCatalog.InOrder;
			foreach (Mutation mutation in inOrder)
			{
				float chancePercent = Mathf.Min(100f, rules.ChanceOf(mutation, stars) * boost);
				if (MayRoll(mutation, ruleSet, barred) && Dice.Percent(chancePercent))
				{
					list.Add(mutation);
				}
			}
			Cap(list, ruleSet.MaxMutations);
			return Pack(list);
		}

		private static void Cap(List<Mutation> hits, int maxMutations)
		{
			if (maxMutations > 0 && hits.Count > maxMutations)
			{
				for (int num = hits.Count - 1; num > 0; num--)
				{
					int num2 = Random.Range(0, num + 1);
					int index = num;
					int index2 = num2;
					Mutation value = hits[num2];
					Mutation value2 = hits[num];
					hits[index] = value;
					hits[index2] = value2;
				}
				hits.RemoveRange(maxMutations, hits.Count - maxMutations);
			}
		}

		private static int Pack(List<Mutation> hits)
		{
			int num = 0;
			foreach (Mutation hit in hits)
			{
				num |= 1 << (int)hit;
			}
			return num;
		}
	}
	public static class TraitStore
	{
		private static readonly int ResolvedHash = StringExtensionMethods.GetStableHashCode("ecr_resolved");

		private static readonly int StarsHash = StringExtensionMethods.GetStableHashCode("ecr_stars");

		private static readonly int MaskHash = StringExtensionMethods.GetStableHashCode("ecr_mask");

		private static readonly int AspectHash = StringExtensionMethods.GetStableHashCode("ecr_aspect");

		private static readonly int AspectExtraHash = StringExtensionMethods.GetStableHashCode("ecr_aspect_extra");

		private static readonly int TierHash = StringExtensionMethods.GetStableHashCode("ecr_tier");

		private static readonly int SireStarsHash = StringExtensionMethods.GetStableHashCode("ecr_sire_stars");

		private static readonly int SireMaskHash = StringExtensionMethods.GetStableHashCode("ecr_sire_mask");

		private static readonly int BiomeHash = StringExtensionMethods.GetStableHashCode("ecr_biome");

		private static readonly int DevouredHealthHash = StringExtensionMethods.GetStableHashCode("ecr_dev_hp");

		private static readonly int DevouredDamageHash = StringExtensionMethods.GetStableHashCode("ecr_dev_dmg");

		private static readonly int DevourReadyAtHash = StringExtensionMethods.GetStableHashCode("ecr_dev_ready");

		private static readonly KeyValuePair<int, int> PhantomOfKey = ZDO.GetHashZDOID("ecr_phantom_of");

		private static readonly KeyValuePair<int, int> CloneOfKey = ZDO.GetHashZDOID("ecr_clone_of");

		private static readonly KeyValuePair<int, int> EchoOfKey = ZDO.GetHashZDOID("ecr_echo_of");

		private static readonly KeyValuePair<int, int> DevouredByKey = ZDO.GetHashZDOID("ecr_devoured_by");

		public static bool IsResolved(ZDO zdo)
		{
			if (zdo != null)
			{
				return zdo.GetBool(ResolvedHash, false);
			}
			return false;
		}

		public static CreatureTraits Load(ZDO zdo)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//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_0080: 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)
			int stars = zdo.GetInt(StarsHash, 0);
			int mask = zdo.GetInt(MaskHash, 0);
			return new CreatureTraits(stars, mask)
			{
				Aspect = (Aspect)zdo.GetInt(AspectHash, 0),
				ExtraAspects = zdo.GetInt(AspectExtraHash, 0),
				PhantomCopy = (zdo.GetZDOID(PhantomOfKey) != ZDOID.None),
				Decoy = (zdo.GetZDOID(CloneOfKey) != ZDOID.None),
				Echo = (zdo.GetZDOID(EchoOfKey) != ZDOID.None),
				Tier = zdo.GetInt(TierHash, 0)
			};
		}

		public static void Save(ZDO zdo, CreatureTraits traits)
		{
			zdo.Set("ecr_stars", traits.Stars);
			zdo.Set("ecr_mask", traits.Mask);
			if (traits.Aspect != Aspect.None)
			{
				zdo.Set("ecr_aspect", (int)traits.Aspect);
			}
			if (traits.ExtraAspects != 0)
			{
				zdo.Set("ecr_aspect_extra", traits.ExtraAspects);
			}
			if (traits.Tier > 0)
			{
				zdo.Set("ecr_tier", traits.Tier);
			}
			zdo.Set("ecr_resolved", true);
		}

		public static void SetSire(ZDO zdo, CreatureTraits? sire)
		{
			zdo.Set("ecr_sire_stars", (sire != null) ? (sire.Stars + 1) : 0);
			zdo.Set("ecr_sire_mask", sire?.Mask ?? 0);
		}

		public static CreatureTraits? TakeSire(ZDO zdo)
		{
			int num = zdo.GetInt(SireStarsHash, 0);
			if (num <= 0)
			{
				return null;
			}
			CreatureTraits result = new CreatureTraits(num - 1, zdo.GetInt(SireMaskHash, 0));
			SetSire(zdo, null);
			return result;
		}

		public static void SetBiome(ZDO zdo, Biome biome)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected I4, but got Unknown
			zdo.Set("ecr_biome", (int)biome);
		}

		public static Biome GetBiome(ZDO zdo)
		{
			return (Biome)zdo.GetInt(BiomeHash, 0);
		}

		public static float GetDevouredHealth(ZDO zdo)
		{
			return zdo.GetFloat(DevouredHealthHash, 0f);
		}

		public static float GetDevouredDamage(ZDO zdo)
		{
			return zdo.GetFloat(DevouredDamageHash, 0f);
		}

		public static void AddDevoured(ZDO zdo, float health, float damage)
		{
			zdo.Set("ecr_dev_hp", GetDevouredHealth(zdo) + health);
			zdo.Set("ecr_dev_dmg", GetDevouredDamage(zdo) + damage);
		}

		public static ZDOID GetDevouredBy(ZDO zdo)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return zdo.GetZDOID(DevouredByKey);
		}

		public static void MarkDevouredBy(ZDO zdo, ZDOID devourer)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			zdo.Set("ecr_devoured_by", devourer);
		}

		public static long GetDevourReadyAt(ZDO zdo)
		{
			return zdo.GetLong(DevourReadyAtHash, 0L);
		}

		public static void SetDevourReadyAt(ZDO zdo, long whenMs)
		{
			zdo.Set("ecr_dev_ready", whenMs);
		}
	}
}
namespace EliteCreaturesReborn.Taming
{
	internal static class GameLevel
	{
		private static readonly int Hash = StringExtensionMethods.GetStableHashCode("ecr_game_level");

		public static int Kept(ZDO zdo)
		{
			return zdo.GetInt(Hash, 0);
		}

		public static void Park(Character creature, ZDO zdo)
		{
			int level = creature.GetLevel();
			if (level > 1)
			{
				zdo.Set(Hash, level, false);
			}
			creature.SetLevel(1);
		}

		public static void Follow(Character creature, ZDO zdo, bool gameStars)
		{
			if (gameStars)
			{
				Restore(creature, zdo);
			}
			else if (!RuleState.Active.KeepsLevel(TraitStore.Load(zdo).Stars, isBoss: false))
			{
				Park(creature, zdo);
			}
		}

		private static void Restore(Character creature, ZDO zdo)
		{
			int num = zdo.GetInt(Hash, 0);
			if (num > 0)
			{
				zdo.Set(Hash, 0, false);
			}
			creature.SetLevel((num > 1) ? num : creature.GetLevel());
		}
	}
	internal static class LocalReload
	{
		public static void Run(ZNetView nview)
		{
			ZNetScene instance = ZNetScene.instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)nview == (Object)null) && nview.IsValid())
			{
				ZDO zDO = nview.GetZDO();
				nview.ResetZDO();
				instance.m_instances.Remove(zDO);
				Object.Destroy((Object)(object)((Component)nview).gameObject);
			}
		}
	}
	internal static class TameHold
	{
		private static readonly int OwnStarsHash = StringExtensionMethods.GetStableHashCode("ecr_stars");

		private static readonly int OwnMaskHash = StringExtensionMethods.GetStableHashCode("ecr_mask");

		private static readonly int HeldStarsHash = StringExtensionMethods.GetStableHashCode("ecr_tame_stars");

		private static readonly int HeldMaskHash = StringExtensionMethods.GetStableHashCode("ecr_tame_mask");

		public static CreatureTraits Rolled(ZDO zdo)
		{
			CreatureTraits creatureTraits = TraitStore.Load(zdo);
			int num = zdo.GetInt(HeldStarsHash, 0);
			if (num > 0)
			{
				creatureTraits.Stars = num;
			}
			creatureTraits.Mask |= zdo.GetInt(HeldMaskHash, 0);
			return creatureTraits;
		}

		public static bool Align(ZDO zdo, int strip)
		{
			bool num = Move(zdo, OwnStarsHash, HeldStarsHash, (strip & 1) != 0);
			bool flag = Move(zdo, OwnMaskHash, HeldMaskHash, (strip & 2) != 0);
			return num || flag;
		}

		private static bool Move(ZDO zdo, int own, int held, bool aside)
		{
			int num = (aside ? own : held);
			int num2 = zdo.GetInt(num, 0);
			if (num2 == 0)
			{
				return false;
			}
			zdo.Set(aside ? held : own, num2, false);
			zdo.Set(num, 0, false);
			return true;
		}
	}
	internal static class TameSettle
	{
		public static bool Settle(Character creature, ZDO zdo)
		{
			int num = TameStrip.Wanted(creature);
			int num2 = TameStrip.Of(zdo);
			bool result = (num | num2) != 0 && TameHold.Align(zdo, num);
			if (num == num2)
			{
				return result;
			}
			TameStrip.Set(zdo, num);
			if ((num & ~num2 & 2) != 0)
			{
				GiveBack(creature, zdo);
			}
			if (((num ^ num2) & 1) != 0)
			{
				GameLevel.Follow(creature, zdo, (num & 1) != 0);
			}
			return true;
		}

		private static void GiveBack(Character creature, ZDO zdo)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			List<PouchStore.Entry> list = PouchStore.Load(zdo);
			if (list.Count > 0)
			{
				PouchDrop.DropAll(list, ((Component)creature).transform.position);
				PouchStore.Save(zdo, new List<PouchStore.Entry>());
			}
		}
	}
	internal static class TameStrip
	{
		public const int Stars = 1;

		public const int Mutations = 2;

		private static readonly int Hash = StringExtensionMethods.GetStableHashCode("ecr_tame_strip");

		public static int Wanted(Character creature)
		{
			if (!creature.IsTamed() || creature.IsBoss())
			{
				return 0;
			}
			return ((!TamedSettings.StarsKept) ? 1 : 0) | ((!TamedSettings.MutationsKept) ? 2 : 0);
		}

		public static int Of(ZDO zdo)
		{
			return zdo.GetInt(Hash, 0);
		}

		public static void Set(ZDO zdo, int strip)
		{
			zdo.Set(Hash, strip, false);
		}

		public static CreatureTraits View(CreatureTraits stored, int strip)
		{
			if ((strip & 1) != 0)
			{
				stored.Stars = 0;
				stored.GameStars = true;
			}
			if ((strip & 2) != 0)
			{
				stored.Mask = 0;
			}
			return stored;
		}
	}
	internal sealed class TameTicker : MonoBehaviour
	{
		private const float Seconds = 1f;

		private float _next;

		private void Update()
		{
			float time = Time.time;
			if (!(time < _next))
			{
				_next = time + 1f;
				Guard.Run("tame watch", TameWatch.Tick);
			}
		}
	}
	internal static class TameWatch
	{
		private static readonly Dictionary<EliteController, int> Applied = new Dictionary<EliteController, int>();

		private static readonly List<EliteController> Scratch = new List<EliteController>();

		public static void Track(EliteController controller)
		{
			if (!controller.Creature.IsBoss())
			{
				Applied[controller] = TameStrip.Of(controller.View.GetZDO());
			}
		}

		public static void Forget(EliteController controller)
		{
			Applied.Remove(controller);
		}

		public static void Tick()
		{
			Scratch.Clear();
			Scratch.AddRange(Applied.Keys);
			foreach (EliteController item in Scratch)
			{
				Check(item);
			}
		}

		private static void Check(EliteController controller)
		{
			ZNetView val = (((Object)(object)controller != (Object)null) ? controller.View : null);
			ZDO val2 = (((Object)(object)val != (Object)null && val.IsValid()) ? val.GetZDO() : null);
			if (val2 != null && Applied.TryGetValue(controller, out var value))
			{
				if (val.IsOwner() && ServerLock.RulesArrived)
				{
					TameSettle.Settle(controller.Creature, val2);
				}
				int num = TameStrip.Of(val2);
				if (num != value)
				{
					CatchUp(controller, val2, num);
				}
			}
		}

		private static void CatchUp(EliteController controller, ZDO zdo, int strip)
		{
			if (!Differs(controller, zdo, strip))
			{
				Applied[controller] = strip;
			}
			else if (!Ridden(controller.Creature))
			{
				Applied.Remove(controller);
				LocalReload.Run(controller.View);
			}
		}

		private static bool Differs(EliteController controller, ZDO zdo, int strip)
		{
			CreatureTraits creatureTraits = TameStrip.View(TraitStore.Load(zdo), strip);
			CreatureTraits traits = controller.Traits;
			if (creatureTraits.Stars == traits.Stars && creatureTraits.Mask == traits.Mask && creatureTraits.GameStars == traits.GameStars)
			{
				return zdo.GetInt(ZDOVars.s_level, 1) != controller.Creature.GetLevel();
			}
			return true;
		}

		private static bool Ridden(Character creature)
		{
			Tameable component = ((Component)creature).GetComponent<Tameable>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.m_saddle != (Object)null)
			{
				return component.m_saddle.HaveValidUser();
			}
			return false;
		}
	}
}
namespace EliteCreaturesReborn.Tally
{
	internal sealed class BossBoard
	{
		public string Fight = "";

		public string BossName = "";

		public List<DamageTally.Entry> Entries = new List<DamageTally.Entry>();

		public static BossBoard? Latest { get; private set; }

		public static bool Remember(BossBoard board)
		{
			if (Latest != null && Latest.Fight == board.Fight)
			{
				return false;
			}
			Latest = board;
			return true;
		}

		public static void Forget()
		{
			Latest = null;
		}

		public void Write(ZPackage pkg)
		{
			pkg.Write(Fight);
			pkg.Write(BossName);
			DamageTally.Write(pkg, Entries);
		}

		public static BossBoard Read(ZPackage pkg)
		{
			BossBoard bossBoard = new BossBoard
			{
				Fight = pkg.ReadString(),
				BossName = pkg.ReadString()
			};
			DamageTally.Read(pkg, bossBoard.Entries);
			return bossBoard;
		}
	}
	internal static class BossBoardRecall
	{
		public const string Ask = "ecr_boss_board_ask";

		public const string Answer = "ecr_boss_board_answer";

		private static ZRoutedRpc? _registeredOn;

		private static Action<BossBoard?>? _pending;

		public static void EnsureRegistered()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null && instance != _registeredOn)
			{
				_registeredOn = instance;
				_pending = null;
				instance.Register("ecr_boss_board_ask", (Action<long>)OnAsk);
				instance.Register<ZPackage>("ecr_boss_board_answer", (Action<long, ZPackage>)OnAnswer);
			}
		}

		public static bool Request(Action<BossBoard?> done)
		{
			if ((Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer() || ZRoutedRpc.instance == null)
			{
				return false;
			}
			EnsureRegistered();
			_pending = done;
			ZRoutedRpc.instance.InvokeRoutedRPC("ecr_boss_board_ask", Array.Empty<object>());
			return true;
		}

		private static void OnAsk(long sender)
		{
			Guard.Run("BossBoardRecall.OnAsk", delegate
			{
				Reply(sender);
			});
		}

		private static void Reply(long sender)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer())
			{
				BossBoard latest = BossBoard.Latest;
				ZPackage val = new ZPackage();
				val.Write(latest != null);
				latest?.Write(val);
				ZRoutedRpc.instance.InvokeRoutedRPC(sender, "ecr_boss_board_answer", new object[1] { val });
			}
		}

		private static void OnAnswer(long sender, ZPackage pkg)
		{
			Guard.Run("BossBoardRecall.OnAnswer", delegate
			{
				Receive(pkg);
			});
		}

		private static void Receive(ZPackage pkg)
		{
			BossBoard bossBoard = (pkg.ReadBool() ? BossBoard.Read(pkg) : null);
			if (bossBoard != null && BossBoard.Latest == null)
			{
				BossBoard.Remember(bossBoard);
			}
			Action<BossBoard?>? pending = _pending;
			_pending = null;
			pending?.Invoke(bossBoard);
		}
	}
	internal static class BossBoardRpc
	{
		public const string Rpc = "ecr_boss_board";

		private static ZRoutedRpc? _registeredOn;

		public static void EnsureRegistered()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null && instance != _registeredOn)
			{
				_registeredOn = instance;
				BossBoard.Forget();
				instance.Register<ZPackage>("ecr_boss_board", (Action<long, ZPackage>)OnBoard);
			}
		}

		public static void Announce(Character boss, ZDO zdo)
		{
			//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_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_0038: 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_002a: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_0066: 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)
			if (AspectStore.GetPhantomOf(zdo) != ZDOID.None || ZRoutedRpc.instance == null)
			{
				return;
			}
			ZDOID tether = AspectStore.GetTether(zdo);
			if (TetherPair.Standing(tether))
			{
				BossCredit.HandOver(zdo, tether);
				return;
			}
			List<DamageTally.Entry> list = DamageTally.Load(zdo);
			ZDOID twin = ((tether != ZDOID.None) ? tether : AspectStore.GetTwin(zdo));
			AddPartner(list, twin);
			if (list.Count > 0)
			{
				Send(new BossBoard
				{
					Fight = FightOf(zdo.m_uid, twin),
					BossName = boss.m_name,
					Entries = list
				});
			}
		}

		private static void AddPartner(List<DamageTally.Entry> entries, ZDOID twin)
		{
			//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_001c: Unknown result type (might be due to invalid IL or missing references)
			ZDO val = ((twin != ZDOID.None && ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(twin) : null);
			if (val == null)
			{
				return;
			}
			foreach (DamageTally.Entry item in DamageTally.Load(val))
			{
				DamageTally.Merge(entries, item.Id, item.Name, item.Damage);
			}
		}

		private unsafe static string FightOf(ZDOID self, ZDOID twin)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			string text = ((object)(*(ZDOID*)(&self))/*cast due to .constrained prefix*/).ToString();
			string text2 = ((twin == ZDOID.None) ? text : ((object)(*(ZDOID*)(&twin))/*cast due to .constrained prefix*/).ToString());
			if (string.CompareOrdinal(text, text2) > 0)
			{
				return text2;
			}
			return text;
		}

		private static void Send(BossBoard board)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			board.Write(val);
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, "ecr_boss_board", new object[1] { val });
		}

		private static void OnBoard(long sender, ZPackage pkg)
		{
			Guard.Run("BossBoardRpc.OnBoard", delegate
			{
				Read(pkg);
			});
		}

		private static void Read(ZPackage pkg)
		{
			BossBoard board = BossBoard.Read(pkg);
			if (BossBoard.Remember(board))
			{
				BossBoardView.Show(board);
			}
		}
	}
	internal sealed class BossBoardView : MonoBehaviour
	{
		private const float Margin = 48f;

		private static BossBoardView? _instance;

		private TMP_Text _text;

		private float _hideAt;

		public static void Show(BossBoard board)
		{
			if (Configuration.ShowBossBoard.Value)
			{
				Replay(board);
			}
		}

		public static bool Replay(BossBoard board)
		{
			BossBoardView bossBoardView = Ensure();
			if ((Object)(object)bossBoardView == (Object)null)
			{
				return false;
			}
			bossBoardView._text.text = Compose(board);
			((Graphic)bossBoardView._text).CrossFadeAlpha(1f, 0f, true);
			bossBoardView._hideAt = Time.time + Mathf.Max(1f, Configuration.BossBoardSeconds.Value);
			((Component)bossBoardView).gameObject.SetActive(true);
			return true;
		}

		private void Update()
		{
			if (Time.time >= _hideAt)
			{
				((Component)this).gameObject.SetActive(false);
			}
		}

		private static BossBoardView? Ensure()
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			if ((Object)(object)_instance != (Object)null)
			{
				return _instance;
			}
			MessageHud instance = MessageHud.instance;
			TMP_Text val = (((Object)(object)instance != (Object)null) ? instance.m_messageCenterText : null);
			if ((Object)(object)val == (Object)null || (Object)(object)((Graphic)val).canvas == (Object)null)
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)((Graphic)val).canvas).transform);
			((Object)val2).name = "ecr_boss_board";
			_instance = val2.AddComponent<BossBoardView>();
			_instance._text = val2.GetComponent<TMP_Text>();
			Place((RectTransform)val2.transform, _instance._text);
			return _instance;
		}

		private static void Place(RectTransform rect, TMP_Text text)
		{
			//IL_000b: 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_0035: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = new Vector2(0f, 0.5f);
			rect.anchorMax = new Vector2(0f, 0.5f);
			rect.pivot = new Vector2(0f, 0.5f);
			rect.anchoredPosition = new Vector2(48f, 0f);
			rect.sizeDelta = new Vector2(520f, 600f);
			text.alignment = (TextAlignmentOptions)513;
			text.enableAutoSizing = false;
			text.fontSize = 24f;
			text.richText = true;
		}

		private static string Compose(BossBoard board)
		{
			string text = ((Localization.instance != null) ? Localization.instance.Localize(board.BossName) : board.BossName);
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("<b>").Append(Lang.Format("ecr_tally_defeated", text)).Append("</b>");
			foreach (DamageTally.Entry item in board.Entries.OrderByDescending((DamageTally.Entry e) => e.Damage))
			{
				stringBuilder.Append("\n<noparse>").Append(item.Name).Append("</noparse>   ")
					.Append(Mathf.RoundToInt(item.Damage).ToString("N0"));
			}
			return stringBuilder.ToString();
		}
	}
	internal static class BossCredit
	{
		public const string Rpc = "ecr_boss_credit";

		private static ZRoutedRpc? _registeredOn;

		public static void EnsureRegistered()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null && instance != _registeredOn)
			{
				_registeredOn = instance;
				instance.Register<ZPackage>("ecr_boss_credit", (Action<long, ZPackage>)OnCredit);
			}
		}

		public static void Add(ZDO hit, Player player, float amount)
		{
			//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_0008: 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)
			ZDOID phantomOf = AspectStore.GetPhantomOf(hit);
			if (phantomOf == ZDOID.None)
			{
				DamageTally.Add(hit, player.GetPlayerID(), player.GetPlayerName(), amount);
			}
			else
			{
				Route(phantomOf, player.GetPlayerID(), player.GetPlayerName(), amount);
			}
		}

		public static void HandOver(ZDO fallen, ZDOID partner)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			foreach (DamageTally.Entry item in DamageTally.Load(fallen))
			{
				Route(partner, item.Id, item.Name, item.Damage);
			}
			DamageTally.Clear(fallen);
		}

		private static void Route(ZDOID boss, long playerId, string playerName, float amount)
		{
			//IL_000c: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			ZDOMan instance = ZDOMan.instance;
			ZDO val = ((instance != null) ? instance.GetZDO(boss) : null);
			if (val != null && val.IsOwner())
			{
				DamageTally.Add(val, playerId, playerName, amount);
				return;
			}
			ZRoutedRpc instance2 = ZRoutedRpc.instance;
			long num = ((val != null) ? val.GetOwner() : 0);
			if (instance2 != null)
			{
				if (num != 0L)
				{
					instance2.InvokeRoutedRPC(num, "ecr_boss_credit", new object[1] { Pack(boss, playerId, playerName, amount) });
				}
				else
				{
					instance2.InvokeRoutedRPC("ecr_boss_credit", new object[1] { Pack(boss, playerId, playerName, amount) });
				}
			}
		}

		private static ZPackage Pack(ZDOID boss, long playerId, string playerName, float amount)
		{
			//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_0006: 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_0013: 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_0022: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(boss);
			val.Write(playerId);
			val.Write(playerName);
			val.Write(amount);
			return val;
		}

		private static void OnCredit(long sender, ZPackage pkg)
		{
			Guard.Run("BossCredit.OnCredit", delegate
			{
				Receive(pkg);
			});
		}

		private static void Receive(ZPackage pkg)
		{
			//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_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			ZDOID val = pkg.ReadZDOID();
			long playerId = pkg.ReadLong();
			string playerName = pkg.ReadString();
			float amount = pkg.ReadSingle();
			ZDOMan instance = ZDOMan.instance;
			ZDO val2 = ((instance != null) ? instance.GetZDO(val) : null);
			if (val2 == null)
			{
				return;
			}
			if (val2.IsOwner())
			{
				DamageTally.Add(val2, playerId, playerName, amount);
				return;
			}
			long owner = val2.GetOwner();
			if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && owner != 0L && owner != ZDOMan.GetSessionID())
			{
				ZRoutedRpc.instance.InvokeRoutedRPC(owner, "ecr_boss_credit", new object[1] { Pack(val, playerId, playerName, amount) });
			}
		}
	}
	internal static class DamageTally
	{
		public sealed class Entry
		{
			public long Id;

			public string Name = "";

			public float Damage;
		}

		private sealed class Open
		{
			public ZDO Zdo;

			public List<Entry> Entries;
		}

		private const float FlushInterval = 1f;

		private static readonly int BossDamageHash = StringExtensionMethods.GetStableHashCode("ecr_boss_dmg");

		private static readonly Dictionary<ZDOID, Open> Opened = new Dictionary<ZDOID, Open>();

		private static readonly List<ZDOID> Closing = new List<ZDOID>();

		private static float _nextFlush;

		public static List<Entry> Load(ZDO zdo)
		{
			//IL_0001: 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_0031: Expected O, but got Unknown
			Flush(zdo.m_uid);
			List<Entry> list = new List<Entry>();
			byte[] byteArray = zdo.GetByteArray(BossDamageHash, (byte[])null);
			if (byteArray != null && byteArray.Length != 0)
			{
				Read(new ZPackage(byteArray), list);
			}
			return list;
		}

		public static void Add(ZDO zdo, long playerId, string playerName, float amount)
		{
			//IL_0006: 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 (!Opened.TryGetValue(zdo.m_uid, out Open value) || value.Zdo != zdo)
			{
				value = new Open
				{
					Zdo = zdo,
					Entries = Load(zdo)
				};
				Opened[zdo.m_uid] = value;
			}
			Merge(value.Entries, playerId, playerName, amount);
		}

		public static void Clear(ZDO zdo)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Opened.Remove(zdo.m_uid);
			zdo.Set(BossDamageHash, new byte[0]);
		}

		public static void FlushDue(float now)
		{
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (Opened.Count == 0 || now < _nextFlush)
			{
				return;
			}
			_nextFlush = now + 1f;
			Closing.Clear();
			Closing.AddRange(Opened.Keys);
			foreach (ZDOID item in Closing)
			{
				Flush(item);
			}
		}

		private static void Flush(ZDOID id)
		{
			//IL_0005: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Expected O, but got Unknown
			if (Opened.TryGetValue(id, out Open value))
			{
				Opened.Remove(id);
				if (((ZDOMan.instance != null) ? ZDOMan.instance.GetZDO(id) : null) == value.Zdo && value.Zdo.m_uid == id && value.Zdo.IsOwner())
				{
					ZPackage val = new ZPackage();
					Write(val, value.Entries);
					value.Zdo.Set(BossDamageHash, val.GetArray());
				}
			}
		}

		public static void Merge(List<Entry> entries, long id, string name, float amount)
		{
			foreach (Entry entry in entries)
			{
				if (entry.Id == id)
				{
					entry.Name = name;
					entry.Damage += amount;
					return;
				}
			}
			entries.Add(new Entry
			{
				Id = id,
				Name = name,
				Damage = amount
			});
		}

		public static void Write(ZPackage pkg, List<Entry> entries)
		{
			pkg.Write(entries.Count);
			foreach (Entry entry in entries)
			{
				pkg.Write(entry.Id);
				pkg.Write(entry.Name);
				pkg.Write(entry.Damage);
			}
		}

		public static void Read(ZPackage pkg, List<Entry> into)
		{
			int num = pkg.ReadInt();
			for (int i = 0; i < num; i++)
			{
				into.Add(new Entry
				{
					Id = pkg.ReadLong(),
					Name = pkg.ReadString(),
					Damage = pkg.ReadSingle()
				});
			}
		}
	}
	internal sealed class TallyFlush : MonoBehaviour
	{
		private void Update()
		{
			Guard.Run("DamageTally.Flush", delegate(float now)
			{
				DamageTally.FlushDue(now);
			}, Time.time);
		}
	}
}
namespace EliteCreaturesReborn.Scaling
{
	public static class AspectDamage
	{
		public static void Outgoing(EliteController attacker, Character victim, HitData hit)
		{
			attacker = EchoLink.Source(attacker);
			CreatureTraits traits = attacker.Traits;
			float num = AspectMath.DamageFactor(traits);
			if (!Mathf.Approximately(num, 1f))
			{
				hit.ApplyModifier(num);
			}
			if (traits.HasAspect(Aspect.Enraged))
			{
				Physical(hit, AspectMath.Boost(AspectMath.Power(Aspect.Enraged, "physical bonus")));
			}
			if (traits.HasAspect(Aspect.Elementalist))
			{
				Elemental(hit, AspectMath.Boost(AspectMath.Power(Aspect.Elementalist, "elemental bonus")));
			}
			if (traits.HasAspect(Aspect.Fixated))
			{
				FixatedDamage.Apply(attacker, victim, hit);
			}
		}

		public static void Incoming(EliteController victim, HitData hit)
		{
			if (victim.Traits.HasAspect(Aspect.Shielded) && IsArrow(hit))
			{
				hit.ApplyModifier(AspectMath.Cut(AspectMath.Power(Aspect.Shielded, "arrow reduction")));
			}
			if (victim.Traits.HasAspect(Aspect.Adaptive))
			{
				AdaptiveResist.Apply(victim, hit);
			}
			if (victim.Traits.HasAspect(Aspect.Tethered))
			{
				TetherLink.Brace(victim, hit);
			}
		}

		private static bool IsArrow(HitData hit)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			if ((int)hit.m_skill != 8)
			{
				return (int)hit.m_skill == 14;
			}
			return true;
		}

		private static void Physical(HitData hit, float factor)
		{
			hit.m_damage.m_blunt *= factor;
			hit.m_damage.m_slash *= factor;
			hit.m_damage.m_pierce *= factor;
		}

		private static void Elemental(HitData hit, float factor)
		{
			hit.m_damage.m_fire *= factor;
			hit.m_damage.m_frost *= factor;
			hit.m_damage.m_lightning *= factor;
			hit.m_damage.m_poison *= factor;
			hit.m_damage.m_spirit *= factor;
		}
	}
	public static class AspectMath
	{
		private const float Floor = 0.05f;

		public static float Power(Aspect aspect, string field)
		{
			return RuleState.Active.Boss.Aspects.PowerOf(aspect, field);
		}

		public static float HealthFactor(CreatureTraits traits)
		{
			float num = 1f;
			if (traits.HasAspect(Aspect.Twin))
			{
				num *= Cut(Power(Aspect.Twin, "less health"));
			}
			if (traits.HasAspect(Aspect.Tethered))
			{
				num *= Cut(Power(Aspect.Tethered, "less health"));
			}
			if (traits.HasAspect(Aspect.Colossal))
			{
				num *= Boost(Power(Aspect.Colossal, "more health"));
			}
			return num;
		}

		public static float SizeFactor(CreatureTraits traits)
		{
			if (!traits.HasAspect(Aspect.Colossal))
			{
				return 1f;
			}
			return Boost(Power(Aspect.Colossal, "bigger"));
		}

		public static float SpeedFactor(CreatureTraits traits)
		{
			if (!traits.HasAspect(Aspect.Colossal))
			{
				return 1f;
			}
			return Cut(Power(Aspect.Colossal, "slower"));
		}

		public static float PhantomHealth(AspectRules rules)
		{
			return Mathf.Max(1f, rules.PowerOf(Aspect.Phantom, "health per tier") * (float)Mathf.Max(1, WorldTier.Current()));
		}

		public static float PhantomHealth()
		{
			return PhantomHealth(RuleState.Active.Boss.Aspects);
		}

		public static float[] PhantomSplits()
		{
			return RuleState.Active.Boss.Aspects.ListOf(Aspect.Phantom, "split at");
		}

		public static float DamageFactor(CreatureTraits traits)
		{
			if (traits.PhantomCopy)
			{
				return Cut(Power(Aspect.Phantom, "less damage"));
			}
			float num = (traits.HasAspect(Aspect.Twin) ? Cut(Power(Aspect.Twin, "less damage")) : 1f);
			if (!traits.HasAspect(Aspect.Tethered))
			{
				return num;
			}
			return num * Cut(Power(Aspect.Tethered, "less damage"));
		}

		public static float Cut(float percentLess)
		{
			return Mathf.Max(0.05f, 1f - percentLess / 100f);
		}

		public static float Boost(float percentMore)
		{
			return Mathf.Max(0f, 1f + percentMore / 100f);
		}
	}
	public static class DamageMath
	{
		public static float OutgoingMultiplier(BiomeRules rules, CreatureTraits traits, float healthFraction)
		{
			float num = rules.Star.AttackAt(traits.Stars) - 1f;
			if (traits.Has(Mutation.Splintering))
			{
				num += rules.PowerOf(Mutation.Splintering, "damage") - 1f;
			}
			if (traits.Has(Mutation.Plated))
			{
				num += Enhance.Magnitude(rules, traits, Mutation.Plated, "damage") / 100f * (1f - healthFraction);
			}
			return Mathf.Max(0f, 1f + num);
		}

		public static float DevouredFlatDamage(CreatureTraits traits, ZDO zdo)
		{
			if (!traits.Has(Mutation.Devouring) || zdo == null)
			{
				return 0f;
			}
			return TraitStore.GetDevouredDamage(zdo);
		}

		public static float PlatedPercent(BiomeRules rules, CreatureTraits traits)
		{
			if (!traits.Has(Mutation.Plated))
			{
				return 0f;
			}
			return Mathf.Min(Enhance.Magnitude(rules, traits, Mutation.Plated, "armour"), rules.PowerOf(Mutation.Plated, "max reduction"));
		}

		public static float PlatedReduction(BiomeRules rules, CreatureTraits traits, float healthFraction)
		{
			return PlatedPercent(rules, traits) / 100f * Mathf.Clamp01(healthFraction);
		}
	}
	public static class Enhance
	{
		public static float Stat(BiomeRules rules, CreatureTraits traits, Mutation mutation, string field)
		{
			float num = rules.PowerOf(mutation, field);
			if (!traits.OnLargeStar(mutation))
			{
				return num;
			}
			return 1f + (num - 1f) * rules.LargeStarPower;
		}

		public static float Magnitude(BiomeRules rules, CreatureTraits traits, Mutation mutation, string field)
		{
			float num = rules.PowerOf(mutation, field);
			if (!traits.OnLargeStar(mutation))
			{
				return num;
			}
			return num * rules.LargeStarPower;
		}
	}
	public static class StatApplier
	{
		public static void ApplySize(Character character, BiomeRules rules, CreatureTraits traits)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			float num = StatMath.SizeMultiplier(rules, traits) * AspectMath.SizeFactor(traits);
			if (!Mathf.Approximately(num, 1f))
			{
				Transform transform = ((Component)character).transform;
				transform.localScale *= num;
			}
		}

		public static void ApplyHealth(Character character, BiomeRules rules, CreatureTraits traits, bool freshlyResolved)
		{
			ZDO zDO = ((Component)character).GetComponent<ZNetView>().GetZDO();
			float num = ((zDO != null && traits.Wears(Mutation.Devouring)) ? TraitStore.GetDevouredHealth(zDO) : 0f);
			float num2 = LevelledBase(character, traits);
			float num3 = (traits.PhantomCopy ? AspectMath.PhantomHealth() : (num2 * StatMath.HealthMultiplier(rules, traits) * AspectMath.HealthFactor(traits) * HordeFactors.Health(character, zDO) + num));
			if (!RuleState.Active.KeepsLevel(traits, character.IsBoss()) || !Mathf.Approximately(num3, num2))
			{
				character.SetMaxHealth(num3);
			}
			if (zDO != null && (freshlyResolved || PinnedAt(zDO, num3)))
			{
				zDO.RemoveFloat(ZDOVars.s_health);
			}
		}

		private static float LevelledBase(Character character, CreatureTraits traits)
		{
			return character.GetMaxHealthBase() * (float)((traits.Stars != 0) ? 1 : Mathf.Max(1, character.GetLevel()));
		}

		private static bool PinnedAt(ZDO zdo, float max)
		{
			return Mathf.Approximately(zdo.GetFloat(ZDOVars.s_health, -1f), max);
		}
	}
	public static class StatMath
	{
		public const float HealthFloor = 0.05f;

		public const float MoveFloor = 0.05f;

		public static float HealthMultiplier(BiomeRules rules, CreatureTraits traits)
		{
			float num = rules.Star.HpAt(traits.Stars) - 1f;
			if (traits.Wears(Mutation.Mad))
			{
				num += rules.PowerOf(Mutation.Mad, "health") - 1f;
			}
			if (traits.Wears(Mutation.Bloated))
			{
				num += Enhance.Stat(rules, traits, Mutation.Bloated, "health") - 1f;
			}
			if (traits.Wears(Mutation.Blinking))
			{
				num += rules.PowerOf(Mutation.Blinking, "health") - 1f;
			}
			return Mathf.Max(0.05f, 1f + num);
		}

		public static float SizeMultiplier(BiomeRules rules, CreatureTraits traits)
		{
			return 1f + rules.Star.GrowthAt(traits.Stars);
		}

		public static float MoveMultiplier(BiomeRules rules, CreatureTraits traits, float devourBonus)
		{
			float num = rules.Star.SpeedAt(traits.Stars) - 1f + devourBonus;
			if (traits.Wears(Mutation.Mad))
			{
				num += Enhance.Stat(rules, traits, Mutation.Mad, "move") - 1f;
			}
			if (traits.Wears(Mutation.Devouring))
			{
				num += rules.PowerOf(Mutation.Devouring, "move") - 1f;
			}
			float num2 = Mathf.Max(0.05f, 1f + num) * AspectMath.SpeedFactor(traits);
			if (!traits.Wears(Mutation.Relentless))
			{
				return num2;
			}
			return Mathf.Min(1f, num2);
		}

		public static float SwingSpeedMultiplier(BiomeRules rules, CreatureTraits traits)
		{
			float num = rules.Star.SwingSpeedAt(traits.Stars) - 1f;
			if (traits.Wears(Mutation.Mad))
			{
				num += Enhance.Stat(rules, traits, Mutation.Mad,