Decompiled source of PraetorisClient v0.1.121

PraetorisClient.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Security;
using System.Net.Sockets;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Authentication;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Common;
using EpicLoot;
using EpicLoot.Abilities;
using EpicLoot.Adventure;
using EpicLoot.Config;
using EpicLoot.MagicItemEffects;
using EpicLoot.ShardStones;
using EpicLoot.src.Magic.MagicItemEffects.Helpers;
using EpicLootAPI;
using EpicLootLeslieAlphaTest.src;
using EpicLootLeslieAlphaTest.src.MagicEffectss;
using EpicLootLeslieAlphaTest.src.StatusEffects;
using EpicLootLeslieAlphaTest.src.StatusEffects.VFX;
using EpicLootLeslieAlphaTest.src.Utilities;
using GUIFramework;
using HarmonyLib;
using JetBrains.Annotations;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PraetorisClient.BodyBounties;
using PraetorisClient.CreatureOwnership;
using PraetorisClient.EpicLootFeature;
using PraetorisClient.GuardStoneFeature;
using PraetorisClient.Maintenance;
using PraetorisClient.NetworkWardFeature;
using PraetorisClient.ServerChestFeature;
using PraetorisClient.ServerGuideFeature;
using PraetorisClient.ShipPasswordFeature;
using PraetorisClient.SurtlingBoats;
using PraetorisClient.Tombstones;
using SoftReferenceableAssets;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.UI;
using ValheimRcon;
using ValheimRcon.Commands;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("PraetorisClient")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PraetorisClient")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("3A303D15-4E60-4110-8EDF-EDF38560FBE2")]
[assembly: AssemblyFileVersion("0.1.121")]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.121.0")]
[module: UnverifiableCode]
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;
		}
	}
}
namespace EpicLootLeslieAlphaTest.src
{
	public static class MagicEffects
	{
		public static void Init()
		{
			MagicItemEffectDefinition magicItemEffectDefinition = new MagicItemEffectDefinition("AncestralSlam", "Ancestral Slam", "Summons ancestral spirit to mirror your attacks for each enemy hit.");
			magicItemEffectDefinition.Requirements.AllowedItemTypes.Add("TwoHandedWeapon");
			magicItemEffectDefinition.Requirements.AllowedSkillTypes.Add((SkillType)3);
			Helpers.Add(magicItemEffectDefinition.Requirements.AllowedRarities, ItemRarity.Epic, ItemRarity.Legendary, ItemRarity.Mythic, ItemRarity.Ancient);
			magicItemEffectDefinition.SelectionWeight = 1f;
			magicItemEffectDefinition.Register();
			MagicItemEffectDefinition magicItemEffectDefinition2 = new MagicItemEffectDefinition("GlancingBlows", "Glancing Blows", "Increases your block value by 50%. Take addtional damage equal to 50% of all blocked or parried hits. This additional damage is only mitigate by player armor and is not reduced from player resistances.");
			Helpers.Add(magicItemEffectDefinition2.Requirements.AllowedItemTypes, "Bucklers", "RoundShields", "TowerShields", "OneHandedWeapon", "TwoHandedWeapon");
			magicItemEffectDefinition2.Requirements.ItemHasBlockPower = true;
			Helpers.Add(magicItemEffectDefinition2.Requirements.AllowedRarities, ItemRarity.Magic, ItemRarity.Rare, ItemRarity.Epic, ItemRarity.Legendary, ItemRarity.Mythic, ItemRarity.Ancient);
			magicItemEffectDefinition2.ValuesPerRarity.Magic.Set(1f, 1f);
			magicItemEffectDefinition2.ValuesPerRarity.Rare = new ValueDef(1f, 1f, 1f);
			magicItemEffectDefinition2.ValuesPerRarity.Epic = new ValueDef(1f, 1f, 1f);
			magicItemEffectDefinition2.ValuesPerRarity.Legendary = new ValueDef(1f, 1f, 1f);
			magicItemEffectDefinition2.ValuesPerRarity.Mythic = new ValueDef(1f, 1f, 1f);
			magicItemEffectDefinition2.ValuesPerRarity.Ancient = new ValueDef(1f, 1f, 1f);
			magicItemEffectDefinition2.SelectionWeight = 5f;
			magicItemEffectDefinition2.Register();
			MagicItemEffectDefinition magicItemEffectDefinition3 = new MagicItemEffectDefinition("Retaliation", "Retaliation +{0}", "On block gain a stack of Relatliation. On Attack consumes a stack of Relataliation to increase the attack speed of your next attack string. All stacks of Retaliation expire after 5 seconds. Consuming or gaining a stack of Retaliation resets the expiration timer.");
			Helpers.Add(magicItemEffectDefinition3.Requirements.AllowedItemTypes, "Bucklers", "RoundShields", "TowerShields", "OneHandedWeapon", "TwoHandedWeapon");
			magicItemEffectDefinition3.Requirements.ItemHasBlockPower = true;
			Helpers.Add(magicItemEffectDefinition3.Requirements.AllowedRarities, ItemRarity.Magic, ItemRarity.Rare, ItemRarity.Epic, ItemRarity.Legendary, ItemRarity.Mythic, ItemRarity.Ancient);
			magicItemEffectDefinition3.ValuesPerRarity.Magic.Set(1f, 1f);
			magicItemEffectDefinition3.ValuesPerRarity.Rare = new ValueDef(2f, 2f, 1f);
			magicItemEffectDefinition3.ValuesPerRarity.Epic = new ValueDef(3f, 3f, 1f);
			magicItemEffectDefinition3.ValuesPerRarity.Legendary = new ValueDef(4f, 4f, 1f);
			magicItemEffectDefinition3.ValuesPerRarity.Mythic = new ValueDef(5f, 5f, 1f);
			magicItemEffectDefinition3.ValuesPerRarity.Ancient = new ValueDef(6f, 6f, 1f);
			magicItemEffectDefinition3.SelectionWeight = 2f;
			magicItemEffectDefinition3.Register();
			MagicItemEffectDefinition magicItemEffectDefinition4 = new MagicItemEffectDefinition("Infusion", "Infusion +{0}%", "Cleanses certain status effects and adds <b><color=yellow>X</color></b>% of weapon damage as their respective type. Certain cleansed status effects grant addittional bonuses.");
			Helpers.Add(magicItemEffectDefinition4.Requirements.AllowedItemTypes, "OneHandedWeapon", "TwoHandedWeapon");
			List<SkillType> allowedSkillTypes = magicItemEffectDefinition4.Requirements.AllowedSkillTypes;
			SkillType[] array = new SkillType[8];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			Helpers.Add(allowedSkillTypes, (SkillType[])(object)array);
			Helpers.Add(magicItemEffectDefinition4.Requirements.AllowedRarities, ItemRarity.Magic, ItemRarity.Rare, ItemRarity.Epic, ItemRarity.Legendary, ItemRarity.Mythic, ItemRarity.Ancient);
			magicItemEffectDefinition4.ValuesPerRarity.Magic.Set(2f, 4f);
			magicItemEffectDefinition4.ValuesPerRarity.Rare = new ValueDef(3f, 6f, 1f);
			magicItemEffectDefinition4.ValuesPerRarity.Epic = new ValueDef(4f, 8f, 1f);
			magicItemEffectDefinition4.ValuesPerRarity.Legendary = new ValueDef(5f, 10f, 1f);
			magicItemEffectDefinition4.ValuesPerRarity.Mythic = new ValueDef(6f, 12f, 1f);
			magicItemEffectDefinition4.ValuesPerRarity.Ancient = new ValueDef(7f, 14f, 1f);
			magicItemEffectDefinition4.SelectionWeight = 2f;
			magicItemEffectDefinition4.Ability = "Infusion";
			AbilityProxyDefinition abilityProxyDefinition = new AbilityProxyDefinition("Infusion", AbilityActivationMode.Activated, typeof(Infusion.InfusionAbilityProxy));
			abilityProxyDefinition.Ability.Cooldown = 120f;
			PrefabManager.OnPrefabsRegistered += delegate
			{
				EpicLoot.RegisterAsset("InfusionIcon", ObjectDB.instance.GetStatusEffect(StringExtensionMethods.GetStableHashCode("SetEffect_MageArmor"))?.m_icon);
			};
			abilityProxyDefinition.Ability.IconAsset = "InfusionIcon";
			magicItemEffectDefinition4.Register();
			MagicItemEffectDefinition magicItemEffectDefinition5 = new MagicItemEffectDefinition("Whirlwind", "Whirlwind", "Spin");
			magicItemEffectDefinition5.Requirements.AllowedItemTypes.Add("TwoHandedWeapon");
			magicItemEffectDefinition5.Requirements.AllowedSkillTypes.Add((SkillType)4);
			Helpers.Add(magicItemEffectDefinition5.Requirements.AllowedRarities, ItemRarity.Epic, ItemRarity.Legendary, ItemRarity.Mythic, ItemRarity.Ancient);
			magicItemEffectDefinition5.SelectionWeight = 1f;
			magicItemEffectDefinition5.Register();
			MagicItemEffectDefinition magicItemEffectDefinition6 = new MagicItemEffectDefinition("Onslaught", "Onslaught +{0}%", "Grants Onslaught on last hit of an attack string and when hitting a staggered enemy. While in last hit of attack string during Onslaught you continue attacking using the last hit animation of your attack string. Each consecutive Onslaught hit deals {0}% increased damage per hit. Onslaught expires if an enemy has not been struck with an attack in last hit animation for 2 seconds.");
			Helpers.Add(magicItemEffectDefinition6.Requirements.AllowedItemTypes, "OneHandedWeapon", "TwoHandedWeapon");
			magicItemEffectDefinition6.Requirements.AllowedSkillTypes.Add((SkillType)3);
			Helpers.Add(magicItemEffectDefinition6.Requirements.AllowedRarities, ItemRarity.Magic, ItemRarity.Rare, ItemRarity.Epic, ItemRarity.Legendary, ItemRarity.Mythic, ItemRarity.Ancient);
			magicItemEffectDefinition6.ValuesPerRarity.Magic.Set(0.5f, 1f, 0.1f);
			magicItemEffectDefinition6.ValuesPerRarity.Rare = new ValueDef(0.5f, 1.5f, 0.1f);
			magicItemEffectDefinition6.ValuesPerRarity.Epic = new ValueDef(1f, 2f, 0.1f);
			magicItemEffectDefinition6.ValuesPerRarity.Legendary = new ValueDef(1.5f, 2.5f, 0.1f);
			magicItemEffectDefinition6.ValuesPerRarity.Mythic = new ValueDef(2f, 3f, 0.1f);
			magicItemEffectDefinition6.ValuesPerRarity.Ancient = new ValueDef(2f, 3f, 0.1f);
			magicItemEffectDefinition6.SelectionWeight = 1f;
			magicItemEffectDefinition6.Register();
		}
	}
}
namespace EpicLootLeslieAlphaTest.src.Utilities
{
	public static class Help
	{
		public static void CopyFieldsFrom<T, V>(this T target, V source) where T : Humanoid where V : Humanoid
		{
			Dictionary<string, FieldInfo> dictionary = typeof(T).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToDictionary((FieldInfo f) => f.Name);
			FieldInfo[] fields = typeof(V).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				if (dictionary.TryGetValue(fieldInfo.Name, out var value) && value.FieldType.IsAssignableFrom(fieldInfo.FieldType))
				{
					value.SetValue(target, fieldInfo.GetValue(source));
				}
			}
		}

		public static void Add<T>(this List<T> list, params T[] values)
		{
			list.AddRange(values);
		}

		public static void Remove<T>(this GameObject prefab) where T : Component
		{
			T val = default(T);
			if (prefab.TryGetComponent<T>(ref val))
			{
				Object.DestroyImmediate((Object)(object)val);
			}
		}
	}
	public class HumanoidFactory
	{
		public static GameObject playerAncestor;

		public static void Create()
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)playerAncestor != (Object)null)
			{
				return;
			}
			GameObject playerPrefab = Game.instance.m_playerPrefab;
			bool activeSelf = playerPrefab.activeSelf;
			playerPrefab.SetActive(false);
			try
			{
				Player component = playerPrefab.GetComponent<Player>();
				playerAncestor = Object.Instantiate<GameObject>(playerPrefab);
				playerAncestor.Remove<AbilityController>();
				playerAncestor.Remove<AdventureComponent>();
				playerAncestor.Remove<Player>();
				playerAncestor.Remove<PlayerController>();
				playerAncestor.Remove<Talker>();
				playerAncestor.Remove<Skills>();
				playerAncestor.Remove<ZSyncTransform>();
				((Object)playerAncestor).name = "playerAncestorHashString";
				playerAncestor.GetComponent<ZNetView>().m_persistent = false;
				playerAncestor.GetComponent<ZNetView>().m_type = (ObjectType)0;
				Humanoid obj = playerAncestor.AddComponent<Humanoid>();
				obj.CopyFieldsFrom<Humanoid, Player>(component);
				((Character)obj).m_animator = playerAncestor.GetComponentInChildren<Animator>();
				((Character)obj).m_zanim = playerAncestor.GetComponent<ZSyncAnimation>();
				((Character)obj).m_body = playerAncestor.GetComponent<Rigidbody>();
				((Character)obj).m_collider = playerAncestor.GetComponent<CapsuleCollider>();
				obj.m_visEquipment = playerAncestor.GetComponent<VisEquipment>();
				((Character)obj).m_turnSpeed = 0f;
				((Character)obj).m_animEvent = playerAncestor.GetComponentInChildren<CharacterAnimEvent>();
				((Character)obj).m_eye = Utils.FindChild(playerAncestor.transform, "EyePos", (IterativeSearchType)0);
				if ((Object)(object)playerAncestor.GetComponent<ZSyncAnimation>() != (Object)null)
				{
					playerAncestor.GetComponent<ZSyncAnimation>().m_animator = playerAncestor.GetComponent<Animator>();
					playerAncestor.GetComponent<ZSyncAnimation>().m_nview = playerAncestor.GetComponent<ZNetView>();
				}
				Rigidbody component2 = playerAncestor.GetComponent<Rigidbody>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.isKinematic = false;
					component2.useGravity = false;
					component2.constraints = (RigidbodyConstraints)126;
				}
				Shader shader = Shader.Find("Sprites/Default");
				Renderer[] componentsInChildren = playerAncestor.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val in componentsInChildren)
				{
					Material[] materials = val.materials;
					if (materials.Length != 0)
					{
						materials[0].shader = shader;
						materials[0].mainTexture = null;
						materials[0].color = new Color(0.3f, 0.5f, 0.9f, 0.03f);
						if (materials.Length > 1)
						{
							materials[1].shader = shader;
							materials[1].mainTexture = null;
							materials[1].color = new Color(0.3f, 0.5f, 0.9f, 0f);
						}
						materials[0].SetColor("_SkinColor", new Color(0.3f, 0.5f, 0.9f, 0.03f));
						val.materials = materials;
					}
				}
				componentsInChildren = playerAncestor.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val2 in componentsInChildren)
				{
					SkinnedMeshRenderer val3 = (SkinnedMeshRenderer)(object)((val2 is SkinnedMeshRenderer) ? val2 : null);
					if (val3 != null && (Object)(object)val3.sharedMesh != (Object)null)
					{
						_ = ((Object)val3.sharedMesh).name;
					}
					else if (val2 is MeshRenderer)
					{
						MeshFilter component3 = ((Component)val2).GetComponent<MeshFilter>();
						if (component3 != null && (Object)(object)component3.sharedMesh != (Object)null)
						{
							_ = ((Object)component3.sharedMesh).name;
						}
					}
				}
				Collider[] componentsInChildren2 = playerAncestor.GetComponentsInChildren<Collider>();
				for (int i = 0; i < componentsInChildren2.Length; i++)
				{
					componentsInChildren2[i].enabled = false;
				}
				ZNetScene.instance.m_namedPrefabs[StringExtensionMethods.GetStableHashCode("playerAncestorHashString")] = playerAncestor;
				playerAncestor.SetActive(false);
			}
			finally
			{
				playerPrefab.SetActive(activeSelf);
			}
		}
	}
	public static class WA
	{
		public static bool IsHeavyWeapon(ItemData item)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			AnimationState animationState = item.m_shared.m_animationState;
			if ((int)animationState != 8 && (int)animationState != 2 && (int)animationState != 7)
			{
				return (int)animationState == 13;
			}
			return true;
		}

		public static bool IsRangedWeapon(ItemData item)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			AnimationState animationState = item.m_shared.m_animationState;
			if ((int)animationState != 3 && (int)animationState != 10 && (int)animationState != 12)
			{
				return (int)animationState == 14;
			}
			return true;
		}

		public static bool IsTwoHanded(ItemData item)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Invalid comparison between Unknown and I4
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Invalid comparison between Unknown and I4
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			AnimationState animationState = item.m_shared.m_animationState;
			if ((int)animationState != 8 && (int)animationState != 2 && (int)animationState != 7 && (int)animationState != 13 && (int)animationState != 15 && (int)animationState != 11)
			{
				return (int)animationState == 0;
			}
			return true;
		}
	}
}
namespace EpicLootLeslieAlphaTest.src.StatusEffects
{
	public static class SERegistry
	{
		public static void RegisterStatusEffects()
		{
			Register<SE_Retaliation>("SE_Retaliation");
			Register<SE_Onslaught>("SE_Onslaught");
			Register<SE_FireInfused>("SE_FireInfused");
			Register<SE_FrostInfused>("SE_FrostInfused");
			Register<SE_LightningInfused>("SE_LightningInfused");
			Register<SE_PoisonInfused>("SE_PoisonInfused");
			Register<SE_WindInfused>("SE_WindInfused");
		}

		private static void Register<T>(string effectName) where T : StatusEffect
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			T val = ScriptableObject.CreateInstance<T>();
			((Object)(object)val).name = effectName;
			((StatusEffect)val).m_name = effectName;
			ItemManager.Instance.AddStatusEffect(new CustomStatusEffect((StatusEffect)(object)val, false));
		}
	}
	public class SE_FireInfused : SE_Stats
	{
		public const string EffectName = "SE_FireInfused";

		private GameObject m_vfxInstance;

		private GameObject m_vfxInstance2;

		private ItemData weapon;

		private float infusedFireDamage;

		public float Efficacy { get; set; }

		public override void Setup(Character character)
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			((SE_Stats)this).Setup(character);
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				Efficacy = Infusion.Efficacy;
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("SwordDyrnwyn");
				object icon;
				if (itemPrefab == null)
				{
					icon = null;
				}
				else
				{
					ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
					icon = ((component != null) ? component.m_itemData.m_shared.m_icons[0] : null);
				}
				((StatusEffect)this).m_icon = (Sprite)icon;
				((StatusEffect)this).m_name = "Fire Infused";
				((StatusEffect)this).m_ttl = 120f;
				Player localPlayer = Player.m_localPlayer;
				weapon = ((localPlayer != null) ? ((Humanoid)localPlayer).GetCurrentWeapon() : null);
				if (weapon != null && !WA.IsRangedWeapon(weapon))
				{
					DamageTypes damage = weapon.GetDamage();
					float totalDamage = ((DamageTypes)(ref damage)).GetTotalDamage();
					float num = (WA.IsHeavyWeapon(weapon) ? 2f : 1f);
					Logger.LogWarning((object)string.Format("[FireInfused] weapon base damage:{0} efficacy:{1} weapon multiplier:{2} added:{3} + {4} * {5}", totalDamage, Efficacy, num, totalDamage * Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.01f), Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.01f) * Efficacy, num));
					infusedFireDamage += totalDamage * Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.01f) + Efficacy * Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.1f) * num;
					weapon.m_shared.m_damages.m_fire += infusedFireDamage;
					Logger.LogWarning((object)$"Added {infusedFireDamage} fire damage");
				}
			}
		}

		public override void Stop()
		{
			((StatusEffect)this).Stop();
			if (weapon != null)
			{
				weapon.m_shared.m_damages.m_fire -= infusedFireDamage;
			}
			if ((Object)(object)m_vfxInstance != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance);
			}
			if ((Object)(object)m_vfxInstance2 != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance2);
			}
		}

		public override void UpdateStatusEffect(float dt)
		{
			((SE_Stats)this).UpdateStatusEffect(dt);
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				if (((Humanoid)Player.m_localPlayer).GetCurrentWeapon() == weapon && (Object)(object)m_vfxInstance == (Object)null)
				{
					CreateVFX();
				}
				else if (((Humanoid)Player.m_localPlayer).GetCurrentWeapon() != weapon && (Object)(object)m_vfxInstance != (Object)null)
				{
					DestroyVFX();
				}
			}
		}

		private void CreateVFX()
		{
			VisEquipment visEquipment = ((Humanoid)Player.m_localPlayer).m_visEquipment;
			if (!WA.IsTwoHanded(weapon))
			{
				m_vfxInstance = Object.Instantiate<GameObject>(InfusionVFX.FireInfusionVFX, visEquipment.m_rightHand);
				m_vfxInstance.SetActive(true);
				return;
			}
			m_vfxInstance = Object.Instantiate<GameObject>(InfusionVFX.FireInfusionVFX, visEquipment.m_rightHand);
			m_vfxInstance2 = Object.Instantiate<GameObject>(InfusionVFX.FireInfusionVFX, visEquipment.m_leftHand);
			m_vfxInstance.SetActive(true);
			m_vfxInstance2.SetActive(true);
		}

		private void DestroyVFX()
		{
			if ((Object)(object)m_vfxInstance != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance);
				m_vfxInstance = null;
			}
			if ((Object)(object)m_vfxInstance2 != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance2);
				m_vfxInstance2 = null;
			}
		}
	}
	public class SE_FrostInfused : SE_Stats
	{
		public const string EffectName = "SE_FrostInfused";

		private GameObject m_vfxInstance;

		private GameObject m_vfxInstance2;

		private ItemData weapon;

		private float infusedFrostDamage;

		public float Efficacy { get; set; }

		public override void Setup(Character character)
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			((SE_Stats)this).Setup(character);
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				Efficacy = Infusion.Efficacy;
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("SwordMistwalker");
				object icon;
				if (itemPrefab == null)
				{
					icon = null;
				}
				else
				{
					ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
					icon = ((component != null) ? component.m_itemData.m_shared.m_icons[0] : null);
				}
				((StatusEffect)this).m_icon = (Sprite)icon;
				((StatusEffect)this).m_name = "Frost Infused";
				((StatusEffect)this).m_ttl = 120f;
				Player localPlayer = Player.m_localPlayer;
				weapon = ((localPlayer != null) ? ((Humanoid)localPlayer).GetCurrentWeapon() : null);
				if (weapon != null && !WA.IsRangedWeapon(weapon))
				{
					DamageTypes damage = weapon.GetDamage();
					float totalDamage = ((DamageTypes)(ref damage)).GetTotalDamage();
					float num = (WA.IsHeavyWeapon(weapon) ? 2f : 1f);
					Logger.LogWarning((object)string.Format("[FrostInfused] weapon base damage:{0} efficacy:{1} weapon multiplier:{2} added:{3} + {4} * {5}", totalDamage, Efficacy, num, totalDamage * Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.01f), Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.01f) * Efficacy, num));
					infusedFrostDamage += totalDamage * Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.01f) + Efficacy * Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.1f) * num;
					weapon.m_shared.m_damages.m_frost += infusedFrostDamage;
					Logger.LogWarning((object)$"Added {infusedFrostDamage} frost damage");
				}
			}
		}

		public override void Stop()
		{
			((StatusEffect)this).Stop();
			if (weapon != null)
			{
				weapon.m_shared.m_damages.m_frost -= infusedFrostDamage;
			}
			if ((Object)(object)m_vfxInstance != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance);
			}
			if ((Object)(object)m_vfxInstance2 != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance2);
			}
		}

		public override void UpdateStatusEffect(float dt)
		{
			((SE_Stats)this).UpdateStatusEffect(dt);
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				if (((Humanoid)Player.m_localPlayer).GetCurrentWeapon() == weapon && (Object)(object)m_vfxInstance == (Object)null)
				{
					CreateVFX();
				}
				else if (((Humanoid)Player.m_localPlayer).GetCurrentWeapon() != weapon && (Object)(object)m_vfxInstance != (Object)null)
				{
					DestroyVFX();
				}
			}
		}

		private void CreateVFX()
		{
			VisEquipment visEquipment = ((Humanoid)Player.m_localPlayer).m_visEquipment;
			if (!WA.IsTwoHanded(weapon))
			{
				m_vfxInstance = Object.Instantiate<GameObject>(InfusionVFX.FrostInfusionVFX, visEquipment.m_rightHand);
				m_vfxInstance.SetActive(true);
				return;
			}
			m_vfxInstance = Object.Instantiate<GameObject>(InfusionVFX.FrostInfusionVFX, visEquipment.m_rightHand);
			m_vfxInstance2 = Object.Instantiate<GameObject>(InfusionVFX.FrostInfusionVFX, visEquipment.m_leftHand);
			m_vfxInstance.SetActive(true);
			m_vfxInstance2.SetActive(true);
		}

		private void DestroyVFX()
		{
			if ((Object)(object)m_vfxInstance != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance);
				m_vfxInstance = null;
			}
			if ((Object)(object)m_vfxInstance2 != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance2);
				m_vfxInstance2 = null;
			}
		}
	}
	public class SE_LightningInfused : SE_Stats
	{
		public const string EffectName = "SE_LightningInfused";

		private GameObject m_vfxInstance;

		private GameObject m_vfxInstance2;

		private ItemData weapon;

		private float infusedLightningDamage;

		public float Efficacy { get; set; }

		public override void Setup(Character character)
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			((SE_Stats)this).Setup(character);
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				Efficacy = Infusion.Efficacy;
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("SwordNiedhoggLightning");
				object icon;
				if (itemPrefab == null)
				{
					icon = null;
				}
				else
				{
					ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
					icon = ((component != null) ? component.m_itemData.m_shared.m_icons[0] : null);
				}
				((StatusEffect)this).m_icon = (Sprite)icon;
				((StatusEffect)this).m_name = "Lightning Infused";
				((StatusEffect)this).m_ttl = 120f;
				Player localPlayer = Player.m_localPlayer;
				weapon = ((localPlayer != null) ? ((Humanoid)localPlayer).GetCurrentWeapon() : null);
				if (weapon != null && !WA.IsRangedWeapon(weapon))
				{
					DamageTypes damage = weapon.GetDamage();
					float totalDamage = ((DamageTypes)(ref damage)).GetTotalDamage();
					float num = (WA.IsHeavyWeapon(weapon) ? 2f : 1f);
					Logger.LogWarning((object)string.Format("[LightningInfused] weapon base damage:{0} efficacy:{1} weapon multiplier:{2} added:{3} + {4} * {5}", totalDamage, Efficacy, num, totalDamage * Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.01f), Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.01f) * Efficacy, num));
					infusedLightningDamage += totalDamage * Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.01f) + Efficacy * Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.1f) * num;
					weapon.m_shared.m_damages.m_lightning += infusedLightningDamage;
					Logger.LogWarning((object)$"Added {infusedLightningDamage} lightning damage");
				}
			}
		}

		public override void Stop()
		{
			((StatusEffect)this).Stop();
			if (weapon != null)
			{
				weapon.m_shared.m_damages.m_lightning -= infusedLightningDamage;
			}
			if ((Object)(object)m_vfxInstance != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance);
			}
			if ((Object)(object)m_vfxInstance2 != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance2);
			}
		}

		public override void UpdateStatusEffect(float dt)
		{
			((SE_Stats)this).UpdateStatusEffect(dt);
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				if (((Humanoid)Player.m_localPlayer).GetCurrentWeapon() == weapon && (Object)(object)m_vfxInstance == (Object)null)
				{
					CreateVFX();
				}
				else if (((Humanoid)Player.m_localPlayer).GetCurrentWeapon() != weapon && (Object)(object)m_vfxInstance != (Object)null)
				{
					DestroyVFX();
				}
			}
		}

		private void CreateVFX()
		{
			VisEquipment visEquipment = ((Humanoid)Player.m_localPlayer).m_visEquipment;
			if (!WA.IsTwoHanded(weapon))
			{
				m_vfxInstance = Object.Instantiate<GameObject>(InfusionVFX.LightningInfusionVFX, visEquipment.m_rightHand);
				m_vfxInstance.SetActive(true);
				return;
			}
			m_vfxInstance = Object.Instantiate<GameObject>(InfusionVFX.LightningInfusionVFX, visEquipment.m_rightHand);
			m_vfxInstance2 = Object.Instantiate<GameObject>(InfusionVFX.LightningInfusionVFX, visEquipment.m_leftHand);
			m_vfxInstance.SetActive(true);
			m_vfxInstance2.SetActive(true);
		}

		private void DestroyVFX()
		{
			if ((Object)(object)m_vfxInstance != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance);
				m_vfxInstance = null;
			}
			if ((Object)(object)m_vfxInstance2 != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance2);
				m_vfxInstance2 = null;
			}
		}
	}
	public class SE_Onslaught : SE_Stats
	{
		public const string EffectName = "SE_Onslaught";

		public int m_stacks;

		public int m_maxStacks = 9999;

		private float m_onslaughtHits;

		private const float m_expire = 2f;

		public override void Setup(Character character)
		{
			((SE_Stats)this).Setup(character);
			if ((Object)(object)character.m_animator != (Object)null)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("MaceIron");
				object icon;
				if (itemPrefab == null)
				{
					icon = null;
				}
				else
				{
					ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
					icon = ((component != null) ? component.m_itemData.m_shared.m_icons[0] : null);
				}
				((StatusEffect)this).m_icon = (Sprite)icon;
				((StatusEffect)this).m_name = "Onslaught Hits";
				((StatusEffect)this).m_flashIcon = true;
				m_stacks++;
			}
		}

		public void AddStack()
		{
			((StatusEffect)this).m_ttl = 2f;
			if (m_stacks < m_maxStacks)
			{
				m_stacks++;
				((StatusEffect)this).m_time = 0f;
			}
		}

		public void ConsumeStack()
		{
			if (m_stacks > 0)
			{
				m_stacks--;
				((StatusEffect)this).m_time = 0f;
			}
		}

		public override void UpdateStatusEffect(float dt)
		{
			((SE_Stats)this).UpdateStatusEffect(dt);
			Player localPlayer = Player.m_localPlayer;
			if (!WA.IsRangedWeapon((localPlayer != null) ? ((Humanoid)localPlayer).GetCurrentWeapon() : null))
			{
				if (m_stacks <= 0 && !((StatusEffect)this).m_character.InAttack())
				{
					((StatusEffect)this).m_character.GetSEMan().RemoveStatusEffect((StatusEffect)(object)this, false);
				}
				if (!((Character)Player.m_localPlayer).InAttack() && ((StatusEffect)this).m_time > 1.5f)
				{
					m_onslaughtHits = 0f;
				}
			}
		}

		public override void ModifyAttack(SkillType skill, ref HitData hitData)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			((SE_Stats)this).ModifyAttack(skill, ref hitData);
			Logger.LogWarning((object)$"stacks{m_stacks}");
			Character character = ((StatusEffect)this).m_character;
			int? num = ((Humanoid)(((character is Humanoid) ? character : null)?)).m_currentAttack?.m_currentAttackCainLevel;
			if (m_stacks > 0 && !(num < 2))
			{
				m_onslaughtHits += 1f;
				Logger.LogWarning((object)$"{m_onslaughtHits}");
				float num2 = 1f + m_onslaughtHits * Player.m_localPlayer.GetTotalActiveMagicEffectValue("Onslaught", 0.01f);
				hitData.ApplyModifier(num2);
			}
		}

		public override string GetIconText()
		{
			return $"{m_onslaughtHits}";
		}
	}
	public class SE_PoisonInfused : SE_Stats
	{
		public const string EffectName = "SE_PoisonInfused";

		private GameObject m_vfxInstance;

		private GameObject m_vfxInstance2;

		private ItemData weapon;

		private float infusedPoisonDamage;

		public float Efficacy { get; set; }

		public override void Setup(Character character)
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			((SE_Stats)this).Setup(character);
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				Efficacy = Infusion.Efficacy;
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("SwordNiedhoggNature");
				object icon;
				if (itemPrefab == null)
				{
					icon = null;
				}
				else
				{
					ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
					icon = ((component != null) ? component.m_itemData.m_shared.m_icons[0] : null);
				}
				((StatusEffect)this).m_icon = (Sprite)icon;
				((StatusEffect)this).m_name = "Poison Infused";
				((StatusEffect)this).m_ttl = 120f;
				Player localPlayer = Player.m_localPlayer;
				weapon = ((localPlayer != null) ? ((Humanoid)localPlayer).GetCurrentWeapon() : null);
				if (weapon != null && !WA.IsRangedWeapon(weapon))
				{
					DamageTypes damage = weapon.GetDamage();
					float totalDamage = ((DamageTypes)(ref damage)).GetTotalDamage();
					float num = (WA.IsHeavyWeapon(weapon) ? 2f : 1f);
					Logger.LogWarning((object)string.Format("[PoisonInfused] weapon base damage:{0} efficacy:{1} weapon multiplier:{2} added:{3} + {4} * {5}", totalDamage, Efficacy, num, totalDamage * Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.01f), Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.01f) * Efficacy, num));
					infusedPoisonDamage += totalDamage * Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.01f) + Efficacy * Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.1f) * num;
					weapon.m_shared.m_damages.m_poison += infusedPoisonDamage;
					Logger.LogWarning((object)$"Added {infusedPoisonDamage} poison damage");
				}
			}
		}

		public override void Stop()
		{
			((StatusEffect)this).Stop();
			if (weapon != null)
			{
				weapon.m_shared.m_damages.m_poison -= infusedPoisonDamage;
			}
			if ((Object)(object)m_vfxInstance != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance);
			}
			if ((Object)(object)m_vfxInstance2 != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance2);
			}
		}

		public override void UpdateStatusEffect(float dt)
		{
			((SE_Stats)this).UpdateStatusEffect(dt);
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				if (((Humanoid)Player.m_localPlayer).GetCurrentWeapon() == weapon && (Object)(object)m_vfxInstance == (Object)null)
				{
					CreateVFX();
				}
				else if (((Humanoid)Player.m_localPlayer).GetCurrentWeapon() != weapon && (Object)(object)m_vfxInstance != (Object)null)
				{
					DestroyVFX();
				}
			}
		}

		private void CreateVFX()
		{
			VisEquipment visEquipment = ((Humanoid)Player.m_localPlayer).m_visEquipment;
			if (!WA.IsTwoHanded(weapon))
			{
				m_vfxInstance = Object.Instantiate<GameObject>(InfusionVFX.PoisonInfusionVFX, visEquipment.m_rightHand);
				m_vfxInstance.SetActive(true);
				return;
			}
			m_vfxInstance = Object.Instantiate<GameObject>(InfusionVFX.PoisonInfusionVFX, visEquipment.m_rightHand);
			m_vfxInstance2 = Object.Instantiate<GameObject>(InfusionVFX.PoisonInfusionVFX, visEquipment.m_leftHand);
			m_vfxInstance.SetActive(true);
			m_vfxInstance2.SetActive(true);
		}

		private void DestroyVFX()
		{
			if ((Object)(object)m_vfxInstance != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance);
				m_vfxInstance = null;
			}
			if ((Object)(object)m_vfxInstance2 != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance2);
				m_vfxInstance2 = null;
			}
		}
	}
	public class SE_Retaliation : SE_Stats
	{
		public const string EffectName = "SE_Retaliation";

		public int m_stacks;

		public int m_maxStacks = 1;

		private const float m_expire = 5f;

		private float baseSpeed = 1f;

		private bool addedRetaliationSpeed;

		private bool amAttacking;

		private static readonly Dictionary<string, float> _animSpeeds = new Dictionary<string, float>
		{
			{ "atgeir_attack", 1.2f },
			{ "atgeir_secondary", 2f },
			{ "knife_stab", 1.2f },
			{ "knife_secondary", 1.1f },
			{ "battleaxe_attack", 1.6f },
			{ "swing_axe", 1.2f },
			{ "swing_longsword", 1.2f },
			{ "mace_secondary", 1.35f },
			{ "spear_poke", 1.2f },
			{ "sword_secondary", 0.5f },
			{ "dualaxes", 1.1f },
			{ "dualaxes_secondary", 1.1f },
			{ "dual_knives", 1.1f },
			{ "dual_knives_secondary", 1.2f },
			{ "greatsword", 1.2f },
			{ "greatsword_secondary", 1.2f },
			{ "swing_sledge", 1.4f },
			{ "unarmed_attack", 2.2f }
		};

		public override void Setup(Character character)
		{
			((SE_Stats)this).Setup(character);
			if ((Object)(object)character.m_animator != (Object)null)
			{
				m_maxStacks = Mathf.RoundToInt(Player.m_localPlayer.GetTotalActiveMagicEffectValue("Retaliation"));
				baseSpeed = character.m_animator.speed;
				character.m_animator.speed = ((Retaliation.AttackType != null && _animSpeeds.TryGetValue(Retaliation.AttackType, out var value)) ? value : 1.2f);
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("ShieldBanded");
				object icon;
				if (itemPrefab == null)
				{
					icon = null;
				}
				else
				{
					ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
					icon = ((component != null) ? component.m_itemData.m_shared.m_icons[3] : null);
				}
				((StatusEffect)this).m_icon = (Sprite)icon;
				((StatusEffect)this).m_name = "Retaliation";
				((StatusEffect)this).m_flashIcon = true;
			}
		}

		public void AddStack()
		{
			((StatusEffect)this).m_ttl = 5f;
			if (m_stacks < m_maxStacks)
			{
				m_stacks++;
				((StatusEffect)this).m_time = 0f;
			}
		}

		public void ConsumeStack()
		{
			if (m_stacks > 0)
			{
				m_stacks--;
				((StatusEffect)this).m_time = 0f;
			}
		}

		public override void UpdateStatusEffect(float dt)
		{
			((SE_Stats)this).UpdateStatusEffect(dt);
			Player localPlayer = Player.m_localPlayer;
			if (!WA.IsRangedWeapon((localPlayer != null) ? ((Humanoid)localPlayer).GetCurrentWeapon() : null))
			{
				if (!((StatusEffect)this).m_character.InAttack() && amAttacking)
				{
					ConsumeStack();
				}
				amAttacking = ((StatusEffect)this).m_character.InAttack();
				if ((Object)(object)((StatusEffect)this).m_character.m_animator != (Object)null && ((StatusEffect)this).m_character.m_animator.speed >= 5f && !addedRetaliationSpeed)
				{
					Animator animator = ((StatusEffect)this).m_character.m_animator;
					animator.speed += ((Retaliation.AttackType != null && _animSpeeds.TryGetValue(Retaliation.AttackType, out var value)) ? value : 1.2f);
					addedRetaliationSpeed = true;
				}
				if ((Object)(object)((StatusEffect)this).m_character.m_animator != (Object)null && ((StatusEffect)this).m_character.m_animator.speed < 5f)
				{
					((StatusEffect)this).m_character.m_animator.speed = ((Retaliation.AttackType != null && _animSpeeds.TryGetValue(Retaliation.AttackType, out var value2)) ? value2 : 1.2f);
				}
				if (m_stacks > 0 && !((StatusEffect)this).m_character.InAttack())
				{
					((StatusEffect)this).m_character.m_animator.speed = baseSpeed;
				}
				if (m_stacks <= 0 && !((StatusEffect)this).m_character.InAttack())
				{
					((StatusEffect)this).m_character.GetSEMan().RemoveStatusEffect((StatusEffect)(object)this, false);
				}
			}
		}

		public override void Stop()
		{
			((StatusEffect)this).Stop();
			if ((Object)(object)((StatusEffect)this).m_character?.m_animator != (Object)null)
			{
				((StatusEffect)this).m_character.m_animator.speed = baseSpeed;
			}
		}

		public override string GetIconText()
		{
			return $"{m_stacks}";
		}
	}
	public class SE_WindInfused : SE_Stats
	{
		public const string EffectName = "SE_WindInfused";

		private GameObject m_vfxInstance;

		private GameObject m_vfxInstance2;

		private ItemData weapon;

		private float infusedWindValue;

		private float baseSpeed = 1f;

		public override void Setup(Character character)
		{
			((SE_Stats)this).Setup(character);
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				weapon = ((Humanoid)Player.m_localPlayer).GetCurrentWeapon();
				baseSpeed = ((StatusEffect)this).m_character.m_animator.speed;
				((StatusEffect)this).m_name = "Wind Infused";
				((StatusEffect)this).m_ttl = 120f;
			}
		}

		public override void Stop()
		{
			((StatusEffect)this).Stop();
			((StatusEffect)this).m_character.m_animator.speed = baseSpeed;
			if ((Object)(object)m_vfxInstance != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance);
			}
			if ((Object)(object)m_vfxInstance2 != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance2);
			}
		}

		public override void UpdateStatusEffect(float dt)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			((SE_Stats)this).UpdateStatusEffect(dt);
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				_ = ((Humanoid)Player.m_localPlayer).m_visEquipment.m_rightItemInstance;
				_ = weapon.m_shared.m_animationState;
				_ = ((Humanoid)Player.m_localPlayer).m_visEquipment.m_rightHand;
				_ = ((Humanoid)Player.m_localPlayer).m_visEquipment.m_leftHand;
				if (((Character)Player.m_localPlayer).InAttack() && ((Humanoid)Player.m_localPlayer).GetCurrentWeapon() == weapon && baseSpeed <= 3f * baseSpeed)
				{
					Animator animator = ((StatusEffect)this).m_character.m_animator;
					float num = (animator.speed += Player.m_localPlayer.GetTotalActiveMagicEffectValue("Infusion", 0.01f));
				}
				if (((Humanoid)Player.m_localPlayer).GetCurrentWeapon() == weapon && (Object)(object)m_vfxInstance == (Object)null)
				{
					CreateVFX();
				}
				else if (((Humanoid)Player.m_localPlayer).GetCurrentWeapon() != weapon && (Object)(object)m_vfxInstance != (Object)null)
				{
					DestroyVFX();
				}
			}
		}

		private void CreateVFX()
		{
			VisEquipment visEquipment = ((Humanoid)Player.m_localPlayer).m_visEquipment;
			if (!WA.IsTwoHanded(weapon))
			{
				m_vfxInstance = Object.Instantiate<GameObject>(InfusionVFX.WindInfusionVFX, visEquipment.m_rightHand);
				m_vfxInstance.SetActive(true);
				PlayAll(m_vfxInstance);
				return;
			}
			m_vfxInstance = Object.Instantiate<GameObject>(InfusionVFX.WindInfusionVFX, visEquipment.m_rightHand);
			m_vfxInstance2 = Object.Instantiate<GameObject>(InfusionVFX.WindInfusionVFX, visEquipment.m_leftHand);
			m_vfxInstance.SetActive(true);
			m_vfxInstance2.SetActive(true);
			PlayAll(m_vfxInstance);
			PlayAll(m_vfxInstance2);
		}

		private void PlayAll(GameObject vfx)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			Light componentInChildren = vfx.GetComponentInChildren<Light>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				((Component)componentInChildren).gameObject.SetActive(false);
			}
			ParticleSystem[] componentsInChildren = vfx.GetComponentsInChildren<ParticleSystem>();
			foreach (ParticleSystem val in componentsInChildren)
			{
				if ((Object)(object)((Component)val).transform == (Object)(object)vfx.transform)
				{
					val.Stop();
					continue;
				}
				MainModule main = val.main;
				((MainModule)(ref main)).loop = true;
				((MainModule)(ref main)).duration = 2f;
				((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(new Color(0.7607843f, 1f, 0.57254905f, 1f));
				val.Play();
			}
		}

		private void DestroyVFX()
		{
			if ((Object)(object)m_vfxInstance != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance);
				m_vfxInstance = null;
			}
			if ((Object)(object)m_vfxInstance2 != (Object)null)
			{
				Object.Destroy((Object)(object)m_vfxInstance2);
				m_vfxInstance2 = null;
			}
		}
	}
}
namespace EpicLootLeslieAlphaTest.src.StatusEffects.VFX
{
	public static class InfusionVFX
	{
		public static GameObject FireInfusionVFX;

		public static GameObject FrostInfusionVFX;

		public static GameObject LightningInfusionVFX;

		public static GameObject PoisonInfusionVFX;

		public static GameObject WindInfusionVFX;

		public static void Init()
		{
			FireInfusionVFX = BuildVFX(ZNetScene.instance.GetPrefab("Torch"), 0.1f);
			FrostInfusionVFX = BuildVFX(ZNetScene.instance.GetPrefab("vfx_Freezing"), 0.3f);
			LightningInfusionVFX = BuildVFX(ZNetScene.instance.GetPrefab("fx_Lightning"), 0.2f);
			PoisonInfusionVFX = BuildVFX(ZNetScene.instance.GetPrefab("vfx_Poison"), 0.2f);
			WindInfusionVFX = BuildVFX(ZNetScene.instance.GetPrefab("vfx_MeadSwimmer"), 0.08f);
		}

		private static GameObject BuildVFX(GameObject source, float scale)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("InfusionVFX_" + ((Object)source).name);
			val.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)val);
			if ((Object)(object)val.GetComponent<TimedDestruction>() != (Object)null)
			{
				Object.Destroy((Object)(object)val.GetComponent<TimedDestruction>());
			}
			ParticleSystem[] componentsInChildren = source.GetComponentsInChildren<ParticleSystem>(true);
			foreach (ParticleSystem val2 in componentsInChildren)
			{
				if (!((Object)(object)((Component)val2).transform == (Object)(object)source.transform))
				{
					GameObject obj = Object.Instantiate<GameObject>(((Component)val2).gameObject, val.transform);
					obj.transform.localPosition = Vector3.zero;
					obj.transform.localRotation = Quaternion.identity;
					Transform transform = obj.transform;
					transform.localScale *= scale;
				}
			}
			return val;
		}
	}
}
namespace EpicLootLeslieAlphaTest.src.MagicEffectss
{
	public class AncestralSlam
	{
		[HarmonyPatch(typeof(Attack), "OnAttackTrigger")]
		public class Attack_Trigger
		{
			public static void Prefix(Attack __instance)
			{
				if (__instance.m_character is Player)
				{
					_lastAttackCainLevel = __instance.m_currentAttackCainLevel;
					_lastAttackAnim = __instance.m_attackAnimation;
					_lastAttackRange = __instance.m_attackRange;
					_lastAttack = __instance;
				}
			}
		}

		[HarmonyPatch(typeof(Character), "Damage")]
		public class Character_Damage_SpawnClone_Patch
		{
			public static void Postfix(Character __instance, HitData hit)
			{
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_0063: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Invalid comparison between Unknown and I4
				//IL_009a: Unknown result type (might be due to invalid IL or missing references)
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
				//IL_00af: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00be: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Invalid comparison between Unknown and I4
				//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
				//IL_006b: Unknown result type (might be due to invalid IL or missing references)
				//IL_006d: Invalid comparison between Unknown and I4
				//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0072: Invalid comparison between Unknown and I4
				//IL_0074: Unknown result type (might be due to invalid IL or missing references)
				//IL_0076: Invalid comparison between Unknown and I4
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_007a: Invalid comparison between Unknown and I4
				//IL_007c: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Invalid comparison between Unknown and I4
				//IL_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_0082: Invalid comparison between Unknown and I4
				//IL_0084: Unknown result type (might be due to invalid IL or missing references)
				//IL_0087: Invalid comparison between Unknown and I4
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				//IL_008c: Invalid comparison between Unknown and I4
				//IL_008e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0091: Invalid comparison between Unknown and I4
				if (((Humanoid)Player.m_localPlayer).GetCurrentWeapon() == null)
				{
					return;
				}
				ItemData currentWeapon = ((Humanoid)Player.m_localPlayer).GetCurrentWeapon();
				if (currentWeapon == null || !currentWeapon.HasMagicEffect("AncestralSlam"))
				{
					return;
				}
				Character attacker = hit.GetAttacker();
				if (!((Object)(object)attacker == (Object)null) && !((Object)(object)attacker != (Object)(object)Player.m_localPlayer) && !ancestralClonesHASH.Contains(((Component)attacker).gameObject))
				{
					SkillType skill = hit.m_skill;
					if ((int)skill == 1 || (int)skill == 3 || (int)skill == 2 || (int)skill == 11 || (int)skill == 7 || (int)skill == 4 || (int)skill == 5 || (int)skill == 8 || (int)skill == 14 || (int)skill == 9 || (int)skill == 10)
					{
						Vector3 position = ((Component)__instance).transform.position;
						Vector3 val = position - ((Component)Player.m_localPlayer).transform.position;
						Vector3 normalized = ((Vector3)(ref val)).normalized;
						SpawnAncestralSlam(rotation: (normalized != Vector3.zero) ? Quaternion.LookRotation(normalized) : ((Component)Player.m_localPlayer).transform.rotation, position: position - normalized * 1.5f, weapon: currentWeapon);
					}
				}
			}
		}

		[HarmonyPatch(typeof(Character), "Damage")]
		public class Character_Clone_Damage_Patch
		{
			public static void Prefix(Character __instance, HitData hit)
			{
				//IL_005a: 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)
				//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)Player.m_localPlayer == (Object)null)
				{
					return;
				}
				ItemData currentWeapon = ((Humanoid)Player.m_localPlayer).GetCurrentWeapon();
				if (currentWeapon == null || !currentWeapon.HasMagicEffect("AncestralSlam"))
				{
					return;
				}
				Character attacker = hit.GetAttacker();
				if (!((Object)(object)attacker == (Object)null) && ancestralClonesHASH.Contains(((Component)attacker).gameObject))
				{
					float skillFactor = ((Character)Player.m_localPlayer).GetSkillFactor(currentWeapon.m_shared.m_skillType);
					float num = Random.Range(0.96f, 1.04f);
					DamageTypes damage = ((DamageTypes)(ref currentWeapon.m_shared.m_damages)).Clone();
					if (_lastAttackCainLevel >= 2)
					{
						((DamageTypes)(ref damage)).Modify((skillFactor * 0.75f + 0.25f) * 2f * num);
					}
					else
					{
						((DamageTypes)(ref damage)).Modify((skillFactor * 0.75f + 0.25f) * num);
					}
					hit.m_damage = damage;
				}
			}
		}

		[HarmonyPatch(typeof(EnemyHud), "ShowHud")]
		internal class EnemyHud_ShowHud_Patch
		{
			private static bool Prefix(Character c)
			{
				return !ancestralClonesHASH.Contains(((Component)c).gameObject);
			}
		}

		private const float damageModifier = 1f;

		private static int _lastAttackCainLevel = 0;

		private static string _lastAttackAnim = "";

		private static Attack _lastAttack = null;

		private static float _lastAttackRange = 2f;

		public static readonly HashSet<GameObject> ancestralClonesHASH = new HashSet<GameObject>();

		internal static void SpawnAncestralSlam(Vector3 position, Quaternion rotation, ItemData weapon)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)HumanoidFactory.playerAncestor == (Object)null))
			{
				GameObject val = Object.Instantiate<GameObject>(HumanoidFactory.playerAncestor, position, rotation);
				ancestralClonesHASH.Add(val);
				val.SetActive(true);
				bool flag = weapon.m_shared.m_secondaryAttack.m_attackAnimation == _lastAttackAnim;
				Humanoid component = val.GetComponent<Humanoid>();
				component.m_rightItem = weapon.Clone();
				val.GetComponent<Animator>();
				((Character)component).m_lookDir = rotation * Vector3.forward;
				((Character)component).StartAttack((Character)null, flag);
				if (component.m_currentAttack != null)
				{
					Attack currentAttack = component.m_currentAttack;
					currentAttack.m_attackRange *= 1.2f;
					component.m_currentAttack.m_currentAttackCainLevel = _lastAttackCainLevel;
					((Character)component).m_zanim.SetTrigger(_lastAttackAnim + _lastAttackCainLevel);
				}
				((MonoBehaviour)component).StartCoroutine(DelayedDestruction(val.GetComponent<ZNetView>(), val, 2.5f));
			}
		}

		private static IEnumerator DelayedDestruction(ZNetView zview, GameObject go, float attackTime)
		{
			yield return (object)new WaitForSeconds(attackTime + 0.5f);
			Character component = go.GetComponent<Character>();
			if ((Object)(object)component != (Object)null)
			{
				EnemyHud instance = EnemyHud.instance;
				if (instance != null)
				{
					instance.RemoveCharacterHud(component);
				}
				Character.Instances.Remove((IMonoUpdater)(object)component);
			}
			ancestralClonesHASH.Remove(go);
			if ((Object)(object)zview != (Object)null && zview.IsOwner())
			{
				ZNetScene.instance.Destroy(((Component)zview).gameObject);
			}
		}
	}
	public static class GlancingBlows
	{
		[HarmonyPatch(typeof(Humanoid), "BlockAttack")]
		public class Block_Attack_GlancingBlowsBlockAttackPrefix_Patch
		{
			public static void Prefix(HitData hit)
			{
				initialHitValue = hit.GetTotalBlockableDamage();
			}
		}

		[HarmonyPatch(typeof(Humanoid), "BlockAttack")]
		public class Block_Attack_GlancingBlowsBlockAttackPostfix_Patch
		{
			public static void Postfix(HitData hit, Character attacker)
			{
				//IL_0082: Unknown result type (might be due to invalid IL or missing references)
				if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.HasActiveMagicEffect("GlancingBlows", out var _))
				{
					float num = initialHitValue * 0.5f;
					float health = ((Character)Player.m_localPlayer).GetHealth();
					float num2 = (float)Math.Round(num - ((Character)Player.m_localPlayer).GetBodyArmor(), 2);
					if (!((Character)Player.m_localPlayer).IsDead() && num2 > 0f)
					{
						((Character)Player.m_localPlayer).SetHealth(health - num2);
						DamageText.instance.ShowText((TextType)0, ((Component)Player.m_localPlayer).transform.position, num2.ToString(), true);
					}
				}
			}
		}

		[HarmonyPatch(typeof(ItemData), "GetBlockPower", new Type[]
		{
			typeof(int),
			typeof(float)
		})]
		public class GlancingBlowsDamage_Patch
		{
			public static void Postfix(float skillFactor, ref float __result)
			{
				if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.HasActiveMagicEffect("GlancingBlows", out var _))
				{
					__result *= 1.5f;
				}
			}
		}

		private static float effectValue = 1f;

		private static float initialHitValue = 0f;
	}
	public static class Infusion
	{
		public enum InfusionElement
		{
			Fire,
			Frost,
			Lightning,
			Poison,
			Wind,
			Blood
		}

		public class InfusionAbilityProxy : Proxy
		{
			public static IEnumerator RechargeAnimation(Player player, float duration)
			{
				((Character)player).m_zanim.SetBool("recharge_lightningstaff", true);
				yield return (object)new WaitForSeconds(duration);
				((Character)player).m_zanim.SetBool("recharge_lightningstaff", false);
				((Character)player).m_zanim.SetTrigger("recharge_lightningstaff_done");
			}

			public override void Activate()
			{
				if (IsOnCooldown() || (Object)(object)Player.m_localPlayer == (Object)null)
				{
					return;
				}
				SetCooldownEndTime(Proxy.GetTime() + Cooldown);
				List<StatusEffect> list = new List<StatusEffect>(((Character)Player.m_localPlayer).GetSEMan().GetStatusEffects());
				isInfused = false;
				Dictionary<InfusionElement, float> dictionary = new Dictionary<InfusionElement, float>();
				List<StatusEffect> list2 = new List<StatusEffect>();
				for (int num = list.Count - 1; num >= 0; num--)
				{
					string text = ((Object)list[num]).name.ToLower();
					foreach (var (value, key) in elementMap)
					{
						if (text.Contains(value))
						{
							float efficacy = GetEfficacy(list[num]);
							list2.Add(list[num]);
							if (!dictionary.ContainsKey(key) || efficacy > dictionary[key])
							{
								dictionary[key] = efficacy;
							}
							break;
						}
					}
				}
				((MonoBehaviour)Player.m_localPlayer).StartCoroutine(DeferRemoveAndApply(list2, dictionary));
				static IEnumerator DeferRemoveAndApply(List<StatusEffect> toRemove, Dictionary<InfusionElement, float> bestEfficacy)
				{
					foreach (StatusEffect item in toRemove)
					{
						((Character)Player.m_localPlayer).GetSEMan().RemoveStatusEffect(item, false);
					}
					yield return null;
					foreach (KeyValuePair<InfusionElement, float> item2 in bestEfficacy)
					{
						Efficacy = item2.Value;
						((Character)Player.m_localPlayer).GetSEMan().AddStatusEffect(StringExtensionMethods.GetStableHashCode($"SE_{item2.Key}Infused"), false, 0, 0f, (short)(-1));
						isInfused = true;
					}
					if (isInfused)
					{
						((MonoBehaviour)Player.m_localPlayer).StartCoroutine(RechargeAnimation(Player.m_localPlayer, 1f));
					}
					if (!isInfused)
					{
						((Character)Player.m_localPlayer).m_zanim.SetTrigger("emote_shrug");
					}
				}
			}
		}

		private static bool isInfused = false;

		private static readonly List<(string keyword, InfusionElement element)> elementMap = new List<(string, InfusionElement)>
		{
			("fire", InfusionElement.Fire),
			("burn", InfusionElement.Fire),
			("frost", InfusionElement.Frost),
			("freez", InfusionElement.Frost),
			("lightning", InfusionElement.Lightning),
			("shock", InfusionElement.Lightning),
			("poison", InfusionElement.Poison),
			("wind", InfusionElement.Wind),
			("aero", InfusionElement.Wind),
			("moder", InfusionElement.Wind),
			("leaf", InfusionElement.Wind),
			("petal", InfusionElement.Wind),
			("blood", InfusionElement.Blood)
		};

		private static readonly Dictionary<string, Func<StatusEffect, float>> efficacyType = new Dictionary<string, Func<StatusEffect, float>>
		{
			{
				"Burning",
				(StatusEffect se) => ((SE_Burning)se).m_fireDamageLeft
			},
			{
				"Frost",
				(StatusEffect se) => ((StatusEffect)(SE_Frost)se).m_ttl * 10f
			},
			{
				"Lightning",
				(StatusEffect se) => (!(se.m_ttl > 0f) || ((Character)Player.m_localPlayer).m_lastHit == null) ? 0f : ((Character)Player.m_localPlayer).m_lastHit.m_damage.m_lightning
			},
			{
				"Poison",
				(StatusEffect se) => ((SE_Poison)se).m_damageLeft
			}
		};

		public static float Efficacy;

		private static float GetEfficacy(StatusEffect se)
		{
			Logger.LogWarning((object)$"GetEfficacy: {((Object)se).name} found {efficacyType.ContainsKey(((Object)se).name)}");
			if (efficacyType.TryGetValue(((Object)se).name, out Func<StatusEffect, float> value))
			{
				return value(se);
			}
			return 0f;
		}
	}
	public static class Onslaught
	{
		[HarmonyPatch(typeof(Character), "Damage")]
		public class Attack_Trigger_Patch
		{
			public static void Prefix(Character __instance, HitData hit)
			{
				Character attacker = hit.GetAttacker();
				Humanoid val = (Humanoid)(object)((attacker is Humanoid) ? attacker : null);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)Player.m_localPlayer != (Object)(object)val) && ((Humanoid)Player.m_localPlayer).GetCurrentWeapon().HasMagicEffect("Onslaught") && ((val.m_currentAttack?.m_currentAttackCainLevel ?? (-1)) >= 2 || __instance.IsStaggering()))
				{
					SEMan sEMan = ((Character)Player.m_localPlayer).GetSEMan();
					SE_Onslaught sE_Onslaught = sEMan.GetStatusEffect(StringExtensionMethods.GetStableHashCode("SE_Onslaught")) as SE_Onslaught;
					if ((Object)(object)sE_Onslaught != (Object)null)
					{
						sE_Onslaught.AddStack();
					}
					else
					{
						(sEMan.AddStatusEffect(StringExtensionMethods.GetStableHashCode("SE_Onslaught"), false, 0, 0f, (short)(-1)) as SE_Onslaught).AddStack();
					}
				}
			}
		}

		[HarmonyPatch(typeof(Attack), "Start")]
		public class Attack_Modify_Chain_Patch
		{
			public static void Postfix(Attack __instance, Humanoid character, ref bool __result)
			{
				if (!((Object)(object)character != (Object)(object)Player.m_localPlayer))
				{
					SE_Onslaught sE_Onslaught = ((Character)character).GetSEMan().GetStatusEffect(StringExtensionMethods.GetStableHashCode("SE_Onslaught")) as SE_Onslaught;
					if (!((Object)(object)sE_Onslaught == (Object)null) && sE_Onslaught.m_stacks > 0 && character.GetCurrentWeapon().HasMagicEffect("Onslaught"))
					{
						__instance.m_currentAttackCainLevel = 2;
						__instance.m_zanim.SetTrigger(__instance.m_attackAnimation + "2");
						sE_Onslaught.ConsumeStack();
					}
				}
			}
		}
	}
	public static class PerfectStrike
	{
		[HarmonyPatch(typeof(Attack), "Start")]
		public static class Attack_PerfectStrikeAnimation_Patch
		{
			public static void Postfix(Attack __instance, Humanoid character)
			{
				if (!((Object)(object)character != (Object)(object)Player.m_localPlayer) && Player.m_localPlayer.HasActiveMagicEffect("PerfectStrike", out var _))
				{
					if (isPerfectStrike)
					{
						int lastPerfectChain = ((_lastPerfectChain == 2) ? 1 : 2);
						__instance.m_currentAttackCainLevel = 2;
						__instance.m_zanim.SetTrigger(__instance.m_attackAnimation + lastPerfectChain);
						_lastPerfectChain = lastPerfectChain;
						_clicked = false;
						isPerfectStrike = false;
						_perfectDamagePending = true;
					}
					_currentAttack = __instance;
					_currentAnim = __instance.m_attackAnimation;
					_currentChain = __instance.m_currentAttackCainLevel;
					_currentAnimSpeed = __instance.m_speedFactor;
					_attackStartTime = Time.time;
				}
			}
		}

		[HarmonyPatch(typeof(PlayerController), "FixedUpdate")]
		public static class Input_AntiSpam_Patch
		{
			public static void Postfix(PlayerController __instance)
			{
				//IL_0295: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance.m_character != (Object)(object)Player.m_localPlayer || !Player.m_localPlayer.HasActiveMagicEffect("PerfectStrike", out var _))
				{
					return;
				}
				if (!((Character)Player.m_localPlayer).InAttack())
				{
					_clicked = false;
					_windowSFXplayed = false;
					if ((Object)(object)_windowVFXInstance != (Object)null)
					{
						Object.Destroy((Object)(object)_windowVFXInstance);
						_windowVFXInstance = null;
					}
					return;
				}
				float value = 0f;
				float num = 0f;
				float num2 = 0f;
				bool flag = _currentAnim != null && _attackDeltas.TryGetValue((_currentAnim, _currentChain, "default"), out value);
				if (flag)
				{
					num = value * 0.5f;
					num2 = value * 0.75f;
				}
				float num3 = Time.time - _attackStartTime;
				bool flag2 = _currentChain == 0 && _currentAnim != null && !_currentAnim.Contains("secondary");
				if (flag && !flag2)
				{
					bool flag3 = num3 >= num && num3 <= num2;
					if (flag3 && (Object)(object)_windowVFXInstance == (Object)null)
					{
						if ((Object)(object)_cleanVFXPrefab == (Object)null)
						{
							GameObject prefab = ZNetScene.instance.GetPrefab("vfx_kiln_addore");
							if ((Object)(object)prefab != (Object)null)
							{
								bool activeSelf = prefab.activeSelf;
								prefab.SetActive(false);
								_cleanVFXPrefab = Object.Instantiate<GameObject>(prefab);
								prefab.SetActive(activeSelf);
								Object.DestroyImmediate((Object)(object)_cleanVFXPrefab.GetComponent<ZNetView>());
							}
						}
						if ((Object)(object)_cleanVFXPrefab != (Object)null)
						{
							GameObject rightItemInstance = ((Humanoid)Player.m_localPlayer).m_visEquipment.m_rightItemInstance;
							Transform val = (((Object)(object)rightItemInstance != (Object)null) ? rightItemInstance.transform : ((Humanoid)Player.m_localPlayer).m_visEquipment.m_rightHand);
							_windowVFXInstance = Object.Instantiate<GameObject>(_cleanVFXPrefab, val);
							_windowVFXInstance.SetActive(true);
							_windowVFXInstance.transform.localPosition = Vector3.zero;
						}
					}
					else if (!flag3 && (Object)(object)_windowVFXInstance != (Object)null)
					{
						Object.Destroy((Object)(object)_windowVFXInstance);
						_windowVFXInstance = null;
					}
				}
				if (ZInput.GetButtonDown("Attack"))
				{
					_nowClicked = Time.time;
					if (!_clicked)
					{
						_clicked = true;
						if (flag)
						{
							isPerfectStrike = num3 >= num && num3 <= num2;
						}
					}
					else
					{
						_ = isPerfectStrike;
					}
				}
				if (isPerfectStrike && !_windowSFXplayed && !flag2)
				{
					GameObject prefab2 = ZNetScene.instance.GetPrefab("sfx_perfectblock");
					if ((Object)(object)prefab2 != (Object)null)
					{
						Object.Instantiate<GameObject>(prefab2, ((Component)Player.m_localPlayer).transform).transform.localPosition = Vector3.zero;
						_windowSFXplayed = true;
					}
				}
				if (Time.time - _nowClicked >= _clickSpam)
				{
					_clicked = false;
				}
			}
		}

		[HarmonyPatch(typeof(Character), "Damage")]
		public static class PerfectStrike_Damage_Patch
		{
			public static void Postfix(Character __instance, HitData hit)
			{
				if (_perfectDamagePending)
				{
					((DamageTypes)(ref hit.m_damage)).Modify(Player.m_localPlayer.GetTotalActiveMagicEffectValue("PerfectStrike", 0.01f));
					_perfectDamagePending = false;
					_windowSFXplayed = false;
				}
			}
		}

		private static float _attackStartTime;

		private static float _clickSpam = 0.25f;

		private static float _nowClicked;

		private static bool _clicked = false;

		private static bool _windowSFXplayed = false;

		private static int _lastPerfectChain = 0;

		private static bool isPerfectStrike = false;

		private static bool _perfectDamagePending = false;

		private static Attack _currentAttack;

		private static string _currentAnim;

		private static int _currentChain;

		private static float _currentAnimSpeed;

		private static GameObject _cleanVFXPrefab;

		private static GameObject _windowVFXInstance;

		private static readonly Dictionary<(string, int, string), float> _attackDeltas = new Dictionary<(string, int, string), float>
		{
			{
				("battleaxe_attack", 0, "default"),
				0.878f
			},
			{
				("battleaxe_attack", 0, "fast"),
				0.599f
			},
			{
				("battleaxe_attack", 1, "default"),
				1.04f
			},
			{
				("battleaxe_attack", 1, "fast"),
				0.761f
			},
			{
				("battleaxe_attack", 2, "default"),
				1.304f
			},
			{
				("battleaxe_attack", 2, "fast"),
				1.078f
			},
			{
				("battleaxe_secondary", 0, "default"),
				0.843f
			},
			{
				("greatsword", 0, "default"),
				1.642f
			},
			{
				("greatsword", 0, "fast"),
				1.258f
			},
			{
				("greatsword", 1, "default"),
				0.839f
			},
			{
				("greatsword", 1, "fast"),
				0.579f
			},
			{
				("greatsword", 2, "default"),
				0.958f
			},
			{
				("greatsword", 2, "fast"),
				0.682f
			},
			{
				("greatsword_secondary", 0, "default"),
				2.125f
			},
			{
				("greatsword_secondary", 0, "fast"),
				1.703f
			},
			{
				("swing_longsword", 0, "default"),
				1.018f
			}
		};
	}
	public static class Retaliation
	{
		[HarmonyPatch(typeof(Humanoid), "BlockAttack")]
		public class Block_Attack_Retaliate_Patch
		{
			public static void Postfix(Humanoid __instance, bool __result)
			{
				if (Player.m_localPlayer.HasActiveMagicEffect("Retaliation", out var _) && __result && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
				{
					SEMan sEMan = ((Character)__instance).GetSEMan();
					SE_Retaliation sE_Retaliation = sEMan.GetStatusEffect(StringExtensionMethods.GetStableHashCode("SE_Retaliation")) as SE_Retaliation;
					if ((Object)(object)sE_Retaliation != (Object)null)
					{
						sE_Retaliation.AddStack();
					}
					else
					{
						(sEMan.AddStatusEffect(StringExtensionMethods.GetStableHashCode("SE_Retaliation"), false, 0, 0f, (short)(-1)) as SE_Retaliation).AddStack();
					}
				}
			}
		}

		[HarmonyPatch(typeof(Attack), "Start")]
		public class Humanoid_Attack_Patch
		{
			private static void Prefix(Attack __instance, Humanoid character)
			{
				if (!((Object)(object)character != (Object)(object)Player.m_localPlayer) && Player.m_localPlayer.HasActiveMagicEffect("Retaliation", out var _))
				{
					AttackType = __instance.m_attackAnimation;
				}
			}
		}

		public static string AttackType;
	}
	public static class Whirlwind
	{
		[HarmonyPatch(typeof(CharacterAnimEvent), "CustomFixedUpdate")]
		[HarmonyPriority(0)]
		public static class Whirlwind_CharAnim_CFU_Patch
		{
			public static void Postfix(CharacterAnimEvent __instance)
			{
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)__instance.m_character == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)__instance.m_character != (Object)(object)Player.m_localPlayer)
				{
					return;
				}
				InWhirlwind = ((Humanoid)Player.m_localPlayer).GetCurrentWeapon().HasMagicEffect("Whirlwind") && (Object)(object)__instance.m_character != (Object)null && __instance.m_character.InAttack() && __instance.m_character.m_secondaryAttackHold && ((Humanoid)__instance.m_character).m_currentAttack.m_attackAnimation == "atgeir_secondary";
				if (InWhirlwind)
				{
					if (__instance.m_animator.speed > 1f && __instance.m_animator.speed != 10f)
					{
						overFlowAnimSpeed = Mathf.Clamp(__instance.m_animator.speed - 2f, 0f, 0.4f);
					}
					__instance.m_animator.speed = 10f;
					WhirlwindDamage = true;
					__instance.m_character.m_attack = false;
					__instance.m_character.m_attackHold = false;
				}
				else if (!__instance.m_character.InAttack())
				{
					WhirlwindDamage = false;
					overFlowAnimSpeed = 0f;
				}
			}
		}

		[HarmonyPatch(typeof(Character), "Damage")]
		public static class Whirlwind_Damage_Patch
		{
			public static void Prefix(Character __instance, HitData hit)
			{
				if (!((Object)(object)hit.GetAttacker() != (Object)(object)Player.m_localPlayer) && InWhirlwind)
				{
					((DamageTypes)(ref hit.m_damage)).Modify(0.4f * (1f + overFlowAnimSpeed));
					hit.m_staggerMultiplier = 1f;
				}
			}
		}

		[HarmonyPatch(typeof(Attack), "GetAttackStamina")]
		public static class Whirlwind_Stamina_Patch
		{
			public static void Postfix(ref float __result)
			{
				if (InWhirlwind)
				{
					__result *= 0.3f;
				}
			}
		}

		private static bool InWhirlwind;

		private static bool WhirlwindDamage;

		private static float overFlowAnimSpeed;
	}
}
namespace EpicLootAPI
{
	[Serializable]
	[PublicAPI]
	public enum AbilityActivationMode
	{
		Passive,
		Triggerable,
		Activated
	}
	[Serializable]
	[PublicAPI]
	public enum AbilityAction
	{
		Custom,
		StatusEffect
	}
	[Serializable]
	[PublicAPI]
	public class AbilityDefinition
	{
		public string ID = "";

		public string IconAsset = "";

		public AbilityActivationMode ActivationMode;

		public float Cooldown;

		public AbilityAction Action;

		public List<string> ActionParams = new List<string>();

		internal static readonly Method API_AddAbility = new Method("AddAbility");

		internal static readonly Method API_UpdateAbility = new Method("UpdateAbility");

		internal static List<AbilityDefinition> Abilities = new List<AbilityDefinition>();

		[Description("Register a status effect ability which activates on player input")]
		public AbilityDefinition(string ID, string iconAsset, float cooldown, string statusEffectName)
		{
			this.ID = ID;
			ActivationMode = AbilityActivationMode.Activated;
			Cooldown = cooldown;
			Action = AbilityAction.StatusEffect;
			ActionParams.Add(statusEffectName);
			IconAsset = iconAsset;
			Abilities.Add(this);
		}

		internal AbilityDefinition(string ID, AbilityActivationMode mode)
		{
			this.ID = ID;
			ActivationMode = mode;
		}

		public AbilityDefinition()
		{
		}

		public static void RegisterAll()
		{
			foreach (AbilityDefinition item in new List<AbilityDefinition>(Abilities))
			{
				item.Register();
			}
		}

		public bool Register()
		{
			string text = JsonConvert.SerializeObject((object)this);
			if (!(API_AddAbility.Invoke(text)[0] is string value))
			{
				return false;
			}
			RunTimeRegistry.Register(this, value);
			Abilities.Remove(this);
			EpicLoot.logger.LogDebug("Registered ability: " + ID);
			return true;
		}

		public bool Update()
		{
			if (!RunTimeRegistry.TryGetValue(this, out string value))
			{
				return false;
			}
			string text = JsonConvert.SerializeObject((object)this);
			bool flag = (bool)(API_UpdateAbility.Invoke(value, text)[0] ?? ((object)false));
			EpicLoot.logger.LogDebug($"Updated ability {ID}: {flag}");
			return flag;
		}
	}
	[PublicAPI]
	public class AbilityProxyDefinition
	{
		public readonly AbilityDefinition Ability;

		public readonly Dictionary<string, Delegate> Callbacks = new Dictionary<string, Delegate>();

		internal static readonly List<AbilityProxyDefinition> ProxyAbilities = new List<AbilityProxyDefinition>();

		internal static readonly Method API_RegisterProxyAbility = new Method("RegisterProxyAbility");

		internal static readonly Method API_UpdateProxyAbility = new Method("UpdateProxyAbility");

		[Description("Register a complex ability behavior using Proxy class")]
		public AbilityProxyDefinition(string ID, AbilityActivationMode mode, Proxy definition)
		{
			Ability = new AbilityDefinition(ID, mode);
			RegisterCallbacks(definition);
			ProxyAbilities.Add(this);
		}

		[Description("Register a complex ability behavior using Proxy class")]
		public AbilityProxyDefinition(string ID, AbilityActivationMode mode, Type type)
		{
			Ability = new AbilityDefinition(ID, mode);
			if (!typeof(Proxy).IsAssignableFrom(type))
			{
				EpicLoot.logger.LogError("Ability Proxy " + ID + " Type " + type.Name + " does not implement Proxy class");
				return;
			}
			try
			{
				object obj = Activator.CreateInstance(type);
				RegisterCallbacks((Proxy)obj);
				ProxyAbilities.Add(this);
			}
			catch (Exception ex)
			{
				EpicLoot.logger.LogError("Failed to create instance of " + type.Name + ": " + ex.Message);
			}
		}

		private void RegisterCallbacks(Proxy implementation)
		{
			Type type = implementation.GetType();
			MethodInfo[] methods = typeof(Proxy).GetMethods();
			foreach (MethodInfo methodInfo in methods)
			{
				try
				{
					Type[] array = (from p in methodInfo.GetParameters()
						select p.ParameterType).ToArray();
					MethodInfo method = type.GetMethod(methodInfo.Name, array);
					if (method == null)
					{
						EpicLoot.logger.LogWarning("Method " + methodInfo.Name + " not found in implementation");
						continue;
					}
					Type type2 = ((!(methodInfo.ReturnType == typeof(void))) ? Expression.GetFuncType(array.Concat(new Type[1] { methodInfo.ReturnType }).ToArray()) : ((array.Length != 0) ? Expression.GetActionType(array) : typeof(Action)));
					Delegate value = Delegate.CreateDelegate(type2, implementation, method);
					Callbacks[methodInfo.Name] = value;
				}
				catch (Exception ex)
				{
					EpicLoot.logger.LogError("Failed to register callback for method " + methodInfo.Name + ": " + ex.Message);
				}
			}
		}

		public static void RegisterAll()
		{
			foreach (AbilityProxyDefinition item in new List<AbilityProxyDefinition>(ProxyAbilities))
			{
				item.Register();
			}
		}

		public bool Register()
		{
			string text = JsonConvert.SerializeObject((object)Ability);
			if (!(API_RegisterProxyAbility.Invoke(text, Callbacks)[0] is string value))
			{
				return false;
			}
			RunTimeRegistry.Register(this, value);
			ProxyAbilities.Remove(this);
			EpicLoot.logger.LogDebug("Registered proxy ability: " + Ability.ID);
			return true;
		}

		public bool Update()
		{
			if (!RunTimeRegistry.TryGetValue(this, out string value))
			{
				return false;
			}
			string text = JsonConvert.SerializeObject((object)Ability);
			bool flag = (bool)(API_UpdateProxyAbility.Invoke(value, text, Callbacks)[0] ?? ((object)false));
			EpicLoot.logger.LogDebug($"Updated proxy ability: {Ability.ID}, {flag}");
			return flag;
		}
	}
	[Description("Functions are converted into delegates when registered to epic loot")]
	[PublicAPI]
	public class Proxy
	{
		protected Player Player;

		public string AbilityID = "";

		public float Cooldown;

		public virtual string CooldownEndKey => "EpicLoot." + AbilityID + ".CooldownEnd";

		public virtual void Initialize(Player player, string id, float cooldown)
		{
			Player = player;
			AbilityID = id;
			Cooldown = cooldown;
		}

		public virtual void OnUpdate()
		{
		}

		public virtual bool ShouldTrigger()
		{
			return false;
		}

		public virtual bool IsOnCooldown()
		{
			if (HasCooldown())
			{
				return GetTime() < GetCooldownEndTime();
			}
			return false;
		}

		public virtual float TimeUntilCooldownEnds()
		{
			return Mathf.Max(0f, GetCooldownEndTime() - GetTime());
		}

		public virtual float PercentCooldownComplete()
		{
			if (HasCooldown() && IsOnCooldown())
			{
				return 1f - TimeUntilCooldownEnds() / Cooldown;
			}
			return 1f;
		}

		public virtual bool CanActivate()
		{
			return !IsOnCooldown();
		}

		public virtual void TryActivate()
		{
			if (CanActivate())
			{
				Activate();
			}
		}

		public virtual void Activate()
		{
			if (HasCooldown())
			{
				float cooldownEndTime = GetTime() + Cooldown;
				SetCooldownEndTime(cooldownEndTime);
			}
		}

		public virtual void ActivateCustomAction()
		{
		}

		public virtual void ActivateStatusEffectAction()
		{
		}

		public virtual bool HasCooldown()
		{
			return Cooldown > 0f;
		}

		public virtual void SetCooldownEndTime(float cooldownEndTime)
		{
			if (!((Object)(object)Player == (Object)null))
			{
				((Character)Player).m_nview.GetZDO().Set(CooldownEndKey, cooldownEndTime);
			}
		}

		public virtual float GetCooldownEndTime()
		{
			if ((Object)(object)Player == (Object)null)
			{
				return 0f;
			}
			return ((Character)Player).m_nview.GetZDO().GetFloat(CooldownEndKey, 0f);
		}

		public virtual void OnRemoved()
		{
		}

		protected static float GetTime()
		{
			return (float)ZNet.instance.GetTimeSeconds();
		}
	}
	public static class EpicLoot
	{
		[PublicAPI]
		public static class ChangeReason
		{
			public const string Enchant = "Enchant";

			public const string Augment = "Augment";

			public const string Disenchant = "Disenchant";

			public const string Rune = "Rune";

			public const string Temper = "Temper";

			public const string Socket = "Socket";

			public const string Unsocket = "Unsocket";

			public const string LootRoll = "LootRoll";

			public const string Transfer = "Transfer";

			public const string AddSocket = "AddSocket";

			public const string Unspecified = "Unspecified";
		}

		public static readonly Logger logger = new Logger();

		private static readonly Method API_GetTotalActiveMagicEffectValue = new Method("GetTotalActiveMagicEffectValue");

		private static readonly Method API_GetTotalActiveMagicEffectValueForWeapon = new Method("GetTotalActiveMagicEffectValueForWeapon");

		private static readonly Method API_HasActiveMagicEffect = new Method("HasActiveMagicEffect");

		private static readonly Method API_HasActiveMagicEffectOnWeapon = new Method("HasActiveMagicEffectOnWeapon");

		private static readonly Method API_GetTotalActiveSetEffectValue = new Method("GetTotalActiveSetEffectValue");

		private static readonly Method API_GetAllActiveMagicEffects = new Method("GetAllActiveMagicEffects");

		private static readonly Method API_GetAllSetMagicEffects = new Method("GetAllActiveSetMagicEffects");

		private static readonly Method API_GetPlayerTotalActiveMagicEffectValue = new Method("GetTotalPlayerActiveMagicEffectValue");

		private static readonly Method API_PlayerHasActiveMagicEffect = new Method("PlayerHasActiveMagicEffect");

		private static readonly Method API_HasLegendaryItem = new Method("HasLegendaryItem");

		private static readonly Method API_HasLegendarySet = new Method("HasLegendarySet");

		private static readonly Method API_RegisterAsset = new Method("RegisterAsset");

		private static readonly Method API_GetMagicItemJson = new Method("GetMagicItemJson");

		private static readonly Method API_RegisterMagicEffectRequirement = new Method("RegisterMagicEffectRequirement", typeof(string), typeof(Func<ItemData, object, string, bool, bool, bool, bool>));

		private static readonly Method API_AddMagicItemChangedListener = new Method("AddMagicItemChangedListener", typeof(Action<ItemData, string>));

		private static readonly Method API_RemoveMagicItemChangedListener = new Method("RemoveMagicItemChangedListener", typeof(Action<ItemData, string>));

		private static readonly Method API_AddLootGeneratedListener = new Method("AddLootGeneratedListener", typeof(Action<ItemData>));

		private static readonly Method API_RemoveLootGeneratedListener = new Method("RemoveLootGeneratedListener", typeof(Action<ItemData>));

		private static readonly Method API_AddBountyCompletedListener = new Method("AddBountyCompletedListener", typeof(Action<Player, string>));

		private static readonly Method API_RemoveBountyCompletedListener = new Method("RemoveBountyCompletedListener", typeof(Action<Player, string>));

		private static readonly Method API_TryMakeMagicItem = new Method("TryMakeMagicItem");

		private static readonly Method API_RollMagicItemJson = new Method("RollMagicItemJson");

		private static readonly Method API_ApplyMagicItemJson = new Method("ApplyMagicItemJson");

		private static readonly Method API_GetLuckFactor = new Method("GetLuckFactor");

		private static readonly Method API_RollEffectCountForRarity = new Method("RollEffectCountForRarity");

		private static readonly Method API_GetLegendaryIDs = new Method("GetLegendaryIDs");

		private static readonly Method API_GetLegendaryInfoJson = new Method("GetLegendaryInfoJson");

		private static readonly Method API_GetAvailableEffectTypes = new Method("GetAvailableEffectTypes");

		private static readonly Method API_AddLootTables = new Method("AddLootTables");

		private static readonly Method API_UpdateLootTables = new Method("UpdateLootTables");

		private static readonly Method API_RegisterInventoryProvider = new Method("RegisterInventoryProvider", typeof(string), typeof(Func<List<ItemData>>), typeof(Func<string, int>), typeof(Func<string, int, int>), typeof(Func<ItemData, int, int>));

		private static readonly Method API_UnregisterInventoryProvider = new Method("UnregisterInventoryProvider");

		private static readonly Method API_RegisterEquipmentProvider = new Method("RegisterEquipmentProvider", typeof(string), typeof(Func<Player, List<ItemData>>));

		private static readonly Method API_UnregisterEquipmentProvider = new Method("UnregisterEquipmentProvider");

		private static readonly Method API_RegisterSacrificeFilter = new Method("RegisterSacrificeFilter", typeof(string), typeof(Func<ItemData, bool>));

		private static readonly Method API_UnregisterSacrificeFilter = new Method("UnregisterSacrificeFilter");

		private static readonly Method API_InvalidatePlayerEffectCache = new Method("InvalidatePlayerEffectCache");

		private static readonly Method API_GetRegisteredProviders = new Method("GetRegisteredProviders");

		private static readonly Method API_GetApiVersion = new Method("GetApiVersion");

		private static readonly Method API_GetPluginVersion = new Method("GetPluginVersion");

		private static readonly Method API_HasEndpoint = new Method("HasEndpoint");

		private static readonly Method API_IsMagicItem = new Method("IsMagicItem");

		private static readonly Method API_TryGetRarity = new Method("TryGetRarity");

		private static readonly Method API_GetRarityCount = new Method("GetRarityCount");

		private static readonly Method API_GetRarityColorByIndex = new Method("GetRarityColorByIndex");

		private static readonly Method API_GetRarityDisplayNameByIndex = new Method("GetRarityDisplayNameByIndex");

		private static readonly Method API_GetItemRarityColor = new Method("GetItemRarityColor");

		private static readonly Method API_IsEpicLootItem = new Method("IsEpicLootItem");

		private static readonly Method API_IsShardStone = new Method("IsShardStone");

		private static readonly Method API_IsRunestone = new Method("IsRunestone");

		private static readonly Method API_IsMagicCraftingMaterial = new Method("IsMagicCraftingMaterial");

		private static readonly Method API_IsUnidentified = new Method("IsUnidentified");

		private static readonly Method API_CanBeMagicItem = new Method("CanBeMagicItem");

		private static readonly Method API_ItemHasMagicEffect = new Method("ItemHasMagicEffect");

		private static readonly Method API_GetAllMagicEffectTypes = new Method("GetAllMagicEffectTypes");

		private static readonly Method API_GetEnchantCostsJson = new Method("GetEnchantCostsJson");

		private static readonly Method API_GetSacrificeProductsJson = new Method("GetSacrificeProductsJson");

		private static readonly Method API_GetItemDisplayName = new Method("GetItemDisplayName");

		private static readonly Method API_GetItemDecoratedName = new Method("GetItemDecoratedName", typeof(ItemData), typeof(string));

		private static readonly Method API_ApplyMagicItemBackground = new Method("ApplyMagicItemBackground", typeof(GameObject), typeof(GameObject), typeof(ItemData), typeof(bool));

		private static readonly Method API_ApplyMagicItemBackgroundToIcon = new Method("ApplyMagicItemBackgroundToIcon", typeof(GameObject), typeof(ItemData));

		[PublicAPI]
		[Description("Send all your custom conversions, effects, item definitions, etc... to Epic Loot")]
		public static void RegisterAll()
		{
			MaterialConversion.RegisterAll();
			MagicItemEffectDefinition.RegisterAll();
			AbilityDefinition.RegisterAll();
			CustomRecipe.RegisterAll();
			Sacrifice.RegisterAll();
			TreasureMap.RegisterAll();
			SecretStashItem.RegisterAll();
			LegendaryInfo.RegisterAll();
			LegendarySetInfo.RegisterAll();
			BountyTarget.RegisterAll();
			AbilityProxyDefinition.RegisterAll();
		}

		[PublicAPI]
		[Description("Register asset into EpicLoot in order to target them in your definitions")]
		public static bool RegisterAsset(string name, object asset)
		{
			bool flag = (bool)(API_RegisterAsset.Invoke(name, asset)[0] ?? ((object)false));
			logger.LogDebug($"Registered asset: {name}, {flag}");
			return flag;
		}

		[PublicAPI]
		public static bool RegisterMagicEffectRequirement(string externalRequirement, Func<ItemData, object, string, bool, bool, bool, bool> requirement)
		{
			bool flag = (bool)(API_RegisterMagicEffectRequirement.Invoke(externalRequirement, requirement)[0] ?? ((object)false));
			logger.LogDebug($"Registered magic effect requirement: {externalRequirement}, {flag}");
			return flag;
		}

		[PublicAPI]
		public static bool HasLegendaryItem(this Player player, string legendaryItemID)
		{
			bool flag = (bool)(API_HasLegendaryItem.Invoke(player, legendaryItemID)[0] ?? ((object)false));
			logger.LogDebug($"Has legendary item: {legendaryItemID}, {flag} ");
			return flag;
		}

		[PublicAPI]
		public static bool HasLegendarySet(this Player player, string legendarySetID, out int count)
		{
			count = 0;
			object[] array = API_HasLegendarySet.Invoke(player, legendarySetID, count);
			count = (int)(array[3] ?? ((object)0));
			bool flag = (bool)(array[0] ?? ((object)false));
			logger.LogDebug($"Has legendary set: {legendarySetID}, {flag}, count: {count}");
			return flag;
		}

		[PublicAPI]
		public static bool HasActiveMagicEffectOnWeapon(Player player, ItemData item, string effectType, out float effectValue)
		{
			effectValue = 0f;
			object[] array = API_HasActiveMagicEffectOnWeapon.Invoke(player, item, effectType, effectValue);
			effectValue = (float)(array[4] ?? ((object)0f));
			bool flag = (bool)(array[0] ?? ((object)false));
			logger.LogDebug($"Has magic effect on weapon: {effectType}, {flag}, value: {effectValue}");
			return flag;
		}

		[PublicAPI]
		public static float GetTotalActiveMagicEffectValue(Player player, ItemData item, string effectType, float scale = 1f)
		{
			float num = (float)(API_GetTotalActiveMagicEffectValue.Invoke(player, item, effectType, scale)[0] ?? ((object)0f));
			logger.LogDebug($"Total magic effect value: {effectType}, amount: {num}");
			return num;
		}

		[PublicAPI]
		public static float GetTotalActiveMagicEffectValueForWeapon(Player player, ItemData item, string effectType, float scale = 1f)
		{
			float num = (float)(API_GetTotalActiveMagicEffectValueForWeapon.Invoke(player, item, effectType, scale)[0] ?? ((object)0f));
			logger.LogDebug($"Total effect on weapon: {effectType}, amount: {num}");
			return num;
		}

		[PublicAPI]
		public static bool HasActiveMagicEffect(Player player, string effectType, ItemData item, out float effectValue)
		{
			effectValue = 0f;
			object[] array = API_HasActiveMagicEffect.Invoke(player, effectType, item, effectValue);
			effectValue = (float)(array[4] ?? ((object)0f));
			bool flag = (bool)(array[0] ?? ((object)false));
			logger.LogDebug($"Has active effect: {effectType}, {flag}, value: {effectValue}");
			return flag;
		}

		[PublicAPI]
		public static float GetTotalActiveSetEffectValue(Player player, string effectType, float scale = 1f)
		{
			float num = (float)(API_GetTotalActiveSetEffectValue.Invoke(player, effectType, scale)[0] ?? ((object)0f));
			logger.LogDebug($"Total effect value: {effectType}, amount: {num}");
			return num;
		}

		[PublicAPI]
		public static List<MagicItemEffect> GetAllActiveMagicEffects(this Player player, string effectType = null)
		{
			List<string> list = (List<string>)(API_GetAllActiveMagicEffects.Invoke(player, effectType)[0] ?? new List<string>());
			if (list.Count <= 0)
			{
				return new List<MagicItemEffect>();
			}
			List<MagicItemEffect> list2 = new List<MagicItemEffect>();
			list2.DeserializeList(list);
			return list2;
		}

		[PublicAPI]
		public static List<MagicItemEffect> GetAllActiveSetMagicEffects(this Player player, string effectType = null)
		{
			List<string> list = (List<string>)(API_GetAllSetMagicEffects.Invoke(player, effectType)[0] ?? new List<string>());
			if (list.Count <= 0)
			{
				return new List<MagicItemEffect>();
			}
			List<MagicItemEffect> list2 = new List<MagicItemEffect>();
			list2.DeserializeList(list);
			return list2;
		}

		private static void DeserializeList<T>(this List<T> output, List<string> input)
		{
			foreach (string item in input)
			{
				try
				{
					T val = JsonConvert.DeserializeObject<T>(item);
					if (val != null)
					{
						output.Add(val);
					}
				}
				catch
				{
					logger.LogWarning("Failed to parse " + typeof(T).Name);
				}
			}
		}

		[PublicAPI]
		public static float GetTotalActiveMagicEffectValue(this Player player, string effectType, float scale = 1f, ItemData ignoreThisItem = null)
		{
			float num = (float)(API_GetPlayerTotalActiveMagicEffectValue.Invoke(player, effectType, scale, ignoreThisItem)[0] ?? ((object)0f));
			logger.LogDebug($"Total magic effect: {effectType}, value: {num}");
			return num;
		}

		[PublicAPI]
		public static bool HasActiveMagicEffect(this Player player, string effectType, out float effectValue, float scale = 1f, ItemData ignoreThisItem = null)
		{
			effectValue = 0f;
			object[] array = API_PlayerHasActiveMagicEffect.Invoke(player, effectType, effectValue, scale, ignoreThisItem);
			effectValue = (float)(array[3] ?? ((object)0f));
			bool flag = (bool)(array[0] ?? ((object)false));
			logger.LogDebug($"Has active magic effect: {effectType}, value: {flag}");
			return flag;
		}

		[PublicAPI]
		public static MagicItem GetMagicItem(this ItemData itemData)
		{
			string text = (string)(API_GetMagicItemJson.Invoke(itemData)[0] ?? "");
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			return JsonConvert.DeserializeObject<MagicItem>(text);
		}

		[PublicAPI]
		public static bool AddMagicItemChangedListener(Action<ItemData, string> listener)
		{
			return (bool)(API_AddMagicItemChangedListener.Invoke(listener)[0] ?? ((object)false));
		}

		[PublicAPI]
		public static bool RemoveMagicItemChangedListener(Action<ItemData, string> listener)
		{
			return (bool)(API_RemoveMagicItemChangedListener.Invoke(listener)[0] ?? ((object)false));
		}

		[PublicAPI]
		public static bool AddLootGeneratedListener(Action<ItemData> listener)
		{
			return (bool)(API_AddLootGeneratedListener.Invoke(listener)[0] ?? ((object)false));
		}

		[PublicAPI]
		public static bool RemoveLootGeneratedListener(Action<ItemData> listener)
		{
			return (bool)(API_RemoveLootGeneratedListener.Invoke(listener)[0] ?? ((object)false));
		}

		[PublicAPI]
		public static bool AddBountyCompletedListener(Action<Player, string> listener)
		{
			return (bool)(API_AddBountyCompletedListener.Invoke(listener)[0] ?? ((object)false));
		}

		[PublicAPI]
		public static bool RemoveBountyCompletedListener(Action<Player, string> listener)
		{
			return (bool)(API_RemoveBountyCompletedListener.Invoke(listener)[0] ?? ((object)false));
		}

		[PublicAPI]
		public static bool TryMakeMagicItem(this ItemData item, ItemRarity rarity, float luck = 0f, string? legendaryID = null)
		{
			bool flag = (bool)(API_TryMakeMagicItem.Invoke(item, (int)rarity, luck, legendaryID ?? "")[0] ?? ((object)false));
			logger.LogDebug($"Made magic item: {item?.m_shared?.m_name}, {rarity}, {flag}");
			return flag;
		}

		[PublicAPI]
		public static MagicItem? RollMagicItem(ItemRarity rarity, ItemData item, float luck = 0f)
		{
			string text = (string)(API_RollMagicItemJson.Invoke((int)rarity, item, luck)[0] ?? "");
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			try
			{
				return JsonConvert.DeserializeObject<MagicItem>(text);
			}
			catch
			{
				logger.LogWarning("Failed to parse rolled magic item");
				return null;
			}
		}

		[PublicAPI]
		public static bool ApplyMagicItem(this ItemData item, MagicItem magicItem)
		{
			if (magicItem == null)
			{
				return false;
			}
			string text = JsonConvert.SerializeObject((object)magicItem);
			return (bool)(API_ApplyMagicItemJson.Invoke(item, text)[0] ?? ((object)false));
		}

		[PublicAPI]
		public static float GetLuckFactor(Vector3 position)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			return (float)(API_GetLuckFactor.Invoke(position)[0] ?? ((object)0f));
		}

		[PublicAPI]
		public static int RollEffectCountForRarity(ItemRarity rarity)
		{
			return (int)(API_RollEffectCountForRarity.Invoke((int)rarity)[0] ?? ((object)0));
		}

		[PublicAPI]
		public static List<string> GetLegendaryIDs(ItemRarity rarity)
		{
			return (List<string>)(API_GetLegendaryIDs.Invoke((int)rarity)[0] ?? new List<string>());
		}

		[PublicAPI]
		public static LegendaryInfo? GetLegendaryInfo(string legendaryID)
		{
			string text = (string)(API_GetLegendaryInfoJson.Invoke(legendaryID)[0] ?? "");
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			try
			{
				return JsonConvert.DeserializeObject<LegendaryInfo>(text);
			}
			catch
			{
				logger.LogWarning("Failed to parse legendary info for " + legendaryID);
				return null;
			}
		}

		[PublicAPI]
		public static List<string> GetAvailableEffectTypes(this ItemData item, ItemRarity rarity, MagicItem? magicI

ValheimEndgame.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Jotunn;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using SoftReferenceableAssets;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;
using YamlDotNet.RepresentationModel;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ValheimEndgame")]
[assembly: AssemblyDescription("Configurable endgame dungeon encounters")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("warpalicious")]
[assembly: AssemblyProduct("ValheimEndgame")]
[assembly: AssemblyCopyright("Copyright © 2026 warpalicious. All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("40D101FA-4FD5-401D-84E8-AD9A9BCDD7BE")]
[assembly: AssemblyFileVersion("1.6.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.6.0.0")]
[module: UnverifiableCode]
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;
		}
	}
}
namespace ValheimEndgame
{
	internal sealed class ClearRoomCommand : ConsoleCommand
	{
		public override string Name => "ve_clearroom";

		public override string Help => "Clear the current encounter room for development: kill its spawned creatures and cancel its remaining spawns.";

		public override bool IsCheat => true;

		public override void Run(string[] args)
		{
			ClearWave();
		}

		internal static void ClearWave()
		{
			Player player = Player.m_localPlayer;
			if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || ((Character)player).IsTeleporting())
			{
				((Terminal)Console.instance).AddString("Finish entering the room or respawning first.");
				return;
			}
			RoomRun[] array = RoomRun.Loaded.Where((RoomRun run) => run.State == RoomState.Active && run.ContainsActiveRoom(((Component)player).transform.position) && run.IsParticipant(player.GetPlayerID())).ToArray();
			if (array.Length != 1)
			{
				((Terminal)Console.instance).AddString("Stand inside the active room of your encounter.");
			}
			else
			{
				array[0].ClearRoomForDevelopment(player);
			}
		}
	}
	internal sealed class EndEncounterCommand : ConsoleCommand
	{
		public override string Name => "ve_endencounter";

		public override string Help => "Abort your encounter without completion credit and recover belongings. Use inside the room or beside its altar.";

		public override bool IsCheat => true;

		public override void Run(string[] args)
		{
			Terminal instance = (Terminal)(object)Console.instance;
			Player player = Player.m_localPlayer;
			if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || ((Character)player).IsTeleporting())
			{
				instance.AddString("Enter the world and finish respawning or teleporting first.");
				return;
			}
			RoomRun[] array = RoomRun.Loaded.Where((RoomRun run) => (Object)(object)run != (Object)null && run.CanEndEncounter(player)).ToArray();
			if (array.Length != 1)
			{
				instance.AddString((array.Length == 0) ? "No available encounter here. Stand inside your room or within 6 metres of its altar." : "Multiple encounters match. Move inside the room you want to end.");
				return;
			}
			array[0].EndEncounter(player);
			instance.AddString("Ending encounter without completion credit. Returning you and recovering belongings beside the Dungeon Master.");
		}
	}
	internal sealed class GiveTabletCommand : ConsoleCommand
	{
		public override string Name => "ve_givetablet";

		public override string Help => "ve_givetablet <1-15> <theme> [room id]: give yourself one tablet with seven attempts. A room id fixes the tablet to that room.";

		public override bool IsCheat => true;

		public override List<string> CommandOptionList()
		{
			return AvailableThemes();
		}

		private static List<string> AvailableThemes()
		{
			RoomCatalog catalog = Plugin.Instance?.Catalog?.Rooms;
			if (catalog == null || !RoomAssets.HasLoadedRooms)
			{
				return new List<string>();
			}
			return (from id in catalog.EnabledRooms.Where(RoomAssets.HasRoom)
				select catalog.ThemeFor(id)).Distinct<string>(StringComparer.Ordinal).OrderBy<string, string>((string theme) => theme, StringComparer.Ordinal).ToList();
		}

		private static List<string> ThemeRooms(string theme)
		{
			RoomCatalog catalog = Plugin.Instance?.Catalog?.Rooms;
			if (catalog == null)
			{
				return new List<string>();
			}
			return RoomAssets.LoadedRooms.Where((string id) => catalog.ThemeFor(id) == theme).OrderBy<string, string>((string id) => id, StringComparer.Ordinal).ToList();
		}

		private static string? MatchTheme(List<string> themes, string requested)
		{
			string text = themes.FirstOrDefault((string value) => value == requested);
			if (text != null)
			{
				return text;
			}
			string[] array = themes.Where((string value) => string.Equals(value, requested, StringComparison.OrdinalIgnoreCase)).ToArray();
			if (array.Length != 1)
			{
				return null;
			}
			return array[0];
		}

		[HarmonyPatch(typeof(Terminal), "tabCycle")]
		[HarmonyPrefix]
		private static void CompleteTab(Terminal __instance, ref string word, ref List<string> options, bool usePrefix)
		{
			CompleteTheme(__instance, ref word, ref options, usePrefix);
		}

		[HarmonyPatch(typeof(Terminal), "updateSearch")]
		[HarmonyPrefix]
		private static void CompleteSearch(Terminal __instance, ref string word, ref List<string> options, bool usePrefix)
		{
			CompleteTheme(__instance, ref word, ref options, usePrefix);
		}

		private static void CompleteTheme(Terminal __instance, ref string word, ref List<string> options, bool usePrefix)
		{
			if (usePrefix)
			{
				return;
			}
			string text = ((TMP_InputField)__instance.m_input).text;
			if (!text.StartsWith("ve_givetablet ", StringComparison.OrdinalIgnoreCase))
			{
				return;
			}
			options = new List<string>();
			string text2 = text.Substring("ve_givetablet ".Length);
			int num = text2.IndexOf(' ');
			if (num >= 0 && int.TryParse(text2.Substring(0, num), NumberStyles.None, CultureInfo.InvariantCulture, out var result) && result >= 1 && result <= 15)
			{
				string requested = text2.Substring(num + 1);
				List<string> list = AvailableThemes();
				string text3 = list.FirstOrDefault((string value) => requested.StartsWith(value + " ", StringComparison.OrdinalIgnoreCase));
				word = ((text3 == null) ? requested : requested.Substring(text3.Length + 1));
				if (text3 == null)
				{
					options = list;
				}
				else
				{
					options = ThemeRooms(text3);
				}
			}
		}

		public override void Run(string[] args)
		{
			Terminal instance = (Terminal)(object)Console.instance;
			if (args.Length < 2 || !int.TryParse(args[0], NumberStyles.None, CultureInfo.InvariantCulture, out var result) || result < 1 || result > 15)
			{
				instance.AddString(((ConsoleCommand)this).Help);
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				instance.AddString("Enter a world before giving yourself a tablet.");
				return;
			}
			if (Plugin.Instance?.Catalog?.Rooms == null || !RoomAssets.HasLoadedRooms)
			{
				instance.AddString("Room configuration and prefabs are not ready.");
				return;
			}
			List<string> list = AvailableThemes();
			string text = MatchTheme(list, string.Join(" ", args.Skip(1)));
			string text2 = null;
			if (text == null && args.Length > 2)
			{
				text = MatchTheme(list, string.Join(" ", args.Skip(1).Take(args.Length - 2)));
				text2 = args[^1];
				if (text != null && !ThemeRooms(text).Contains(text2))
				{
					instance.AddString("Specify a loaded " + text + " room: " + string.Join(", ", ThemeRooms(text)));
					return;
				}
			}
			if (text == null)
			{
				instance.AddString("Specify an available theme: " + string.Join(", ", list));
				return;
			}
			ItemData val = TabletItem.Create(result);
			Tablet tablet = Tablet.Read(val);
			tablet.Theme = text;
			tablet.Room = text2;
			tablet.Save();
			val.m_cheated = true;
			Inventory inventory = ((Humanoid)localPlayer).GetInventory();
			if (!inventory.CanAddItem(val, 1) || !inventory.AddItem(val))
			{
				instance.AddString("Your inventory has no room for a tablet.");
				return;
			}
			((Character)localPlayer).ShowPickupMessage(val, 1);
			instance.AddString($"Added Tier {result} {text2 ?? text} tablet with {tablet.Attempts} attempts.");
		}
	}
	internal sealed class NextWaveCommand : ConsoleCommand
	{
		public override string Name => "ve_nextwave";

		public override string Help => "Clear the current wave for development. The next wave starts normally; use the exit after a room's final wave.";

		public override bool IsCheat => true;

		public override void Run(string[] args)
		{
			if (args.Length != 0)
			{
				((Terminal)Console.instance).AddString(((ConsoleCommand)this).Help);
			}
			else
			{
				ClearRoomCommand.ClearWave();
			}
		}
	}
	internal sealed class RewardOddsCommand : ConsoleCommand
	{
		public override string Name => "ve_rewardodds";

		public override string Help => "ve_rewardodds <1-15> [modifier bonus percent]: show completion reward rolls and rarity probabilities.";

		public override void Run(string[] args)
		{
			double result = 0.0;
			int num = args.Length;
			bool flag = ((num < 1 || num > 2) ? true : false);
			if (flag || !int.TryParse(args[0], out var result2) || result2 < 1 || result2 > 15 || (args.Length == 2 && !double.TryParse(args[1], NumberStyles.Float, CultureInfo.InvariantCulture, out result)) || double.IsNaN(result) || double.IsInfinity(result) || result < 0.0 || result > 10000.0)
			{
				((Terminal)Console.instance).AddString(((ConsoleCommand)this).Help);
				return;
			}
			RewardCatalog rewardCatalog = Plugin.Instance?.Catalog?.Rewards;
			if (rewardCatalog == null)
			{
				((Terminal)Console.instance).AddString("Enter a world with a valid reward configuration first.");
				return;
			}
			((Terminal)Console.instance).AddString($"Tier {result2}: {rewardCatalog.Rolls(result2, result)} reward rolls; modifier difficulty {result:0.##}%.");
			foreach (KeyValuePair<string, double> item in rewardCatalog.EffectiveProbabilities(result2))
			{
				((Terminal)Console.instance).AddString($"{item.Key}: {item.Value:P2} per roll; {rewardCatalog.AtLeastOne(result2, result, item.Value):P2} for at least one in the completed encounter.");
			}
		}
	}
	internal sealed class SetPlayerTierCommand : ConsoleCommand
	{
		public override string Name => "ve_setplayertier";

		public override string Help => "ve_setplayertier <0-15>: admin only. Mark Tiers 1 to N completed for you in this world's quest ledger. 0 resets progression.";

		public override bool IsCheat => true;

		public override void Run(string[] args)
		{
			Terminal instance = (Terminal)(object)Console.instance;
			if (args.Length != 1 || !int.TryParse(args[0], NumberStyles.None, CultureInfo.InvariantCulture, out var result) || result < 0 || result > 15)
			{
				instance.AddString(((ConsoleCommand)this).Help);
				return;
			}
			if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)QuestService.Instance == (Object)null)
			{
				instance.AddString("Enter a world before setting your progress tier.");
				return;
			}
			QuestService.Instance.SetProgress(result);
			instance.AddString($"Requested progress tier {result}. The Dungeon Master would sell {TabletProgression.Describe(result)}.");
		}
	}
	internal static class ConfigurationLoader
	{
		internal static RewardCatalog LoadRewardDefaults()
		{
			return RewardCatalog.Load(ReadEmbedded("rewards.yaml"));
		}

		internal static EventCatalog Load(string directory, bool useCustomConfiguration)
		{
			RoomCatalog rooms = LoadFile<RoomCatalog>("rooms.yaml", RoomCatalog.Load);
			RewardCatalog rewards = LoadFile<RewardCatalog>("rewards.yaml", RewardCatalog.Load);
			EventCatalog eventCatalog = LoadFile<EventCatalog>("events.yaml", (string yaml) => EventCatalog.Load(yaml, rooms, rewards));
			eventCatalog.Monsters = LoadFile<MonsterCatalog>("creatures.yaml", MonsterCatalog.Load);
			return eventCatalog;
			T LoadFile<T>(string file, Func<string, T> parse)
			{
				string text = (useCustomConfiguration ? Path.Combine(directory, file) : ("embedded " + file));
				try
				{
					if (!useCustomConfiguration)
					{
						return parse(ReadEmbedded(file));
					}
					if (!File.Exists(text))
					{
						Directory.CreateDirectory(directory);
						using FileStream stream = new FileStream(text, FileMode.CreateNew, FileAccess.Write);
						using StreamWriter streamWriter = new StreamWriter(stream);
						streamWriter.Write(ReadEmbedded(file));
					}
					return parse(File.ReadAllText(text));
				}
				catch (Exception ex)
				{
					throw new InvalidOperationException("Invalid configuration in " + text + ": " + ex.GetBaseException().Message, ex);
				}
			}
		}

		private static string ReadEmbedded(string file)
		{
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ValheimEndgame." + file) ?? throw new InvalidOperationException("Missing embedded configuration: " + file);
			using StreamReader streamReader = new StreamReader(stream);
			return streamReader.ReadToEnd();
		}
	}
	public sealed class EventCatalog
	{
		public int SchemaVersion { get; set; }

		public List<EventDefinition> Events { get; set; } = new List<EventDefinition>();

		public TabletBalance Tablets { get; set; } = new TabletBalance();

		public RewardCatalog? Rewards { get; set; }

		public RoomCatalog? Rooms { get; set; }

		public MonsterCatalog? Monsters { get; set; }

		public bool CanResolve(int tier)
		{
			if (Monsters != null && Events.Any((EventDefinition e) => e.Enabled))
			{
				return Monsters.Supports(tier);
			}
			return false;
		}

		public EventDefinition? Resolve(int tier)
		{
			if (!CanResolve(tier))
			{
				return null;
			}
			EventDefinition eventDefinition = Events.FirstOrDefault((EventDefinition e) => e.Enabled && e.Tier == tier);
			EventDefinition eventDefinition2 = Monsters.Build(tier, eventDefinition ?? Events.First((EventDefinition e) => e.Enabled));
			eventDefinition2.Rewards = Rewards ?? throw new InvalidOperationException("Missing rewards.yaml configuration.");
			return eventDefinition2;
		}

		public static EventCatalog Load(string yaml, RoomCatalog? rooms = null, RewardCatalog? rewards = null)
		{
			EventCatalog eventCatalog = Yaml.ConfigurationReader.Deserialize<EventCatalog>(yaml);
			if (eventCatalog == null || eventCatalog.SchemaVersion != 6 || eventCatalog.Events == null || eventCatalog.Events.Count == 0)
			{
				throw new ArgumentException("Expected schemaVersion: 6 with rewards in rewards.yaml.");
			}
			if (eventCatalog.Events.Any((EventDefinition e) => e == null) || eventCatalog.Events.Select((EventDefinition e) => e.Id).Distinct().Count() != eventCatalog.Events.Count || eventCatalog.Events.Select((EventDefinition e) => e.Tier).Distinct().Count() != eventCatalog.Events.Count)
			{
				throw new ArgumentException("Event IDs and tiers must be unique.");
			}
			foreach (EventDefinition @event in eventCatalog.Events)
			{
				@event.Validate();
			}
			if (rewards != null)
			{
				eventCatalog.Rewards = rewards;
			}
			if (eventCatalog.Rewards == null)
			{
				throw new ArgumentException("Missing rewards.yaml configuration.");
			}
			eventCatalog.Rewards.Validate();
			eventCatalog.Monsters?.Validate();
			if (rooms != null)
			{
				eventCatalog.Rooms = rooms;
			}
			if (eventCatalog.Rooms == null)
			{
				throw new ArgumentException("Missing room configuration.");
			}
			eventCatalog.Rooms.Validate();
			if (eventCatalog.Tablets == null || new float[11]
			{
				eventCatalog.Tablets.TotemRadius,
				eventCatalog.Tablets.MovementSlowPercent,
				eventCatalog.Tablets.AttackSlowPercent,
				eventCatalog.Tablets.EitrDrainPercent,
				eventCatalog.Tablets.HealthDrainPercent,
				eventCatalog.Tablets.FireDamage,
				eventCatalog.Tablets.FrostDamage,
				eventCatalog.Tablets.HazardDamagePerTierPercent,
				eventCatalog.Tablets.FireballOrbDamage,
				eventCatalog.Tablets.IceShardOrbDamage,
				eventCatalog.Tablets.MistileOrbDamage
			}.Any((float n) => float.IsNaN(n) || float.IsInfinity(n) || n < 0f || n > 500f))
			{
				throw new ArgumentException("Tablet percentages must be finite and between 0 and 500.");
			}
			if (eventCatalog.Tablets.TotemRadius <= 0f)
			{
				throw new ArgumentException("Totem radius must be positive.");
			}
			if (new float[3]
			{
				eventCatalog.Tablets.MovementSlowPercent,
				eventCatalog.Tablets.AttackSlowPercent,
				eventCatalog.Tablets.ProtectionReductionPercent
			}.Any((float n) => float.IsNaN(n) || float.IsInfinity(n) || n < 0f || n > 80f))
			{
				throw new ArgumentException($"Totem slows and protection must be between 0 and {80f} percent per totem.");
			}
			if (eventCatalog.Tablets.EitrDrainPercent > 100f || eventCatalog.Tablets.HealthDrainPercent > 100f)
			{
				throw new ArgumentException("Totem drains must be between 0 and 100 percent of maximum per second per totem.");
			}
			return eventCatalog;
		}
	}
	public sealed class EventDefinition
	{
		public const int WavesPerRoom = 3;

		public string Id { get; set; } = "";

		public int Tier { get; set; }

		public bool Enabled { get; set; }

		public string StartMessage { get; set; } = "";

		public string EndMessage { get; set; } = "";

		public float SpawnInterval { get; set; } = 2f;

		public float GroupDelay { get; set; } = 8f;

		public int MaxAlive { get; set; } = 8;

		public RewardCatalog? Rewards { get; set; }

		public List<List<CreatureEntry>> Waves { get; set; } = new List<List<CreatureEntry>>();

		public void Validate()
		{
			if (string.IsNullOrWhiteSpace(Id) || Tier < 1 || Tier > 15 || !Finite(SpawnInterval) || SpawnInterval < 0.1f || !Finite(GroupDelay) || GroupDelay < 0f || MaxAlive < 1 || MaxAlive > 100 || Waves == null || Waves.Count > 15)
			{
				throw new ArgumentException("Invalid encounter ID, tier, pacing, or groups.");
			}
			foreach (List<CreatureEntry> wave in Waves)
			{
				if (wave == null || wave.Count == 0 || wave.Any((CreatureEntry e) => e == null || string.IsNullOrWhiteSpace(e.Prefab) || !new string[5] { "standard", "magic", "rare", "miniboss", "boss" }.Contains(e.Role) || e.Amount < 1 || e.Amount > 100 || e.Stars < 0 || e.Stars > 10000 || e.MinStars.HasValue != e.MaxStars.HasValue || e.MinStars < 0 || e.MaxStars > 10000 || e.MaxStars < e.MinStars) || wave.Sum((CreatureEntry e) => e.Amount) > 500)
				{
					throw new ArgumentException("Invalid prefab, count, or stars.");
				}
				foreach (CreatureEntry item in wave)
				{
					if (item.Modifiers != null && item.Modifiers.Groups.Any((List<string> g) => g?.Any(string.IsNullOrWhiteSpace) ?? true))
					{
						throw new ArgumentException("Empty SLS modifier name.");
					}
				}
			}
		}

		private static bool Finite(float n)
		{
			if (!float.IsNaN(n))
			{
				return !float.IsInfinity(n);
			}
			return false;
		}

		public int ThemeBossStage()
		{
			int num = Waves.FindLastIndex((List<CreatureEntry> entries) => entries.Any((CreatureEntry entry) => entry.Role == "boss"));
			if (num >= 0)
			{
				return num / 3;
			}
			return -1;
		}
	}
	public sealed class CreatureEntry
	{
		public string Prefab { get; set; } = "";

		public string Role { get; set; } = "standard";

		public int Amount { get; set; }

		public int Stars { get; set; }

		public bool WorldStars { get; set; }

		public int? MinStars { get; set; }

		public int? MaxStars { get; set; }

		public CreatureModifiers? Modifiers { get; set; }
	}
	public sealed class CreatureModifiers
	{
		public List<string> Major { get; set; } = new List<string>();

		public List<string> Minor { get; set; } = new List<string>();

		public List<string> Boss { get; set; } = new List<string>();

		[YamlIgnore]
		public IEnumerable<List<string>> Groups => new List<string>[3] { Major, Minor, Boss };
	}
	public sealed class MonsterCatalog
	{
		public const int MinimumTier = 1;

		public const int MaximumTier = 15;

		public const int StarsPerTier = 3;

		private static readonly string[] Roles = new string[7] { "standard", "magic", "rare", "miniboss", "boss", "hazard", "excluded" };

		private readonly Dictionary<string, IReadOnlyList<string>> rosters = new Dictionary<string, IReadOnlyList<string>>(StringComparer.Ordinal);

		public int SchemaVersion { get; set; }

		public string Notes { get; set; } = "";

		public Dictionary<string, CatalogCreature> Creatures { get; set; } = new Dictionary<string, CatalogCreature>();

		public List<string> Minibosses { get; set; } = new List<string>();

		public List<string> Bosses { get; set; } = new List<string>();

		public List<WavePlan> Layout { get; set; } = new List<WavePlan>();

		public static MonsterCatalog Load(string yaml)
		{
			MonsterCatalog obj = Yaml.ConfigurationReader.Deserialize<MonsterCatalog>(yaml) ?? throw new ArgumentException("Empty creature catalog.");
			obj.Validate();
			return obj;
		}

		public void Validate()
		{
			rosters.Clear();
			if (SchemaVersion != 2)
			{
				throw new ArgumentException("Expected creatures.yaml schemaVersion: 2.");
			}
			if (Creatures == null || Minibosses == null || Bosses == null || Layout == null || Layout.Count != 10)
			{
				throw new ArgumentException("Invalid creature catalog or ten-wave layout.");
			}
			foreach (KeyValuePair<string, CatalogCreature> creature in Creatures)
			{
				CatalogCreature value = creature.Value;
				if (string.IsNullOrWhiteSpace(creature.Key) || value == null || !Roles.Contains(value.Role) || value.Biomes == null || value.Biomes.Any(string.IsNullOrWhiteSpace) || value.WaveLimits == null || (value.Enabled && (value.Role == "excluded" || value.Stars == null)))
				{
					throw new ArgumentException("Invalid catalog creature: " + creature.Key);
				}
				if (value.Stars != null && (value.Stars.MinStars < 0 || value.Stars.MaxStars < value.Stars.MinStars || value.Stars.MaxStars > 9958))
				{
					throw new ArgumentException("Invalid Tier 1 star range: " + creature.Key);
				}
				if (value.WaveLimits.Any((KeyValuePair<int, int> limit) => limit.Key < 1 || limit.Key > 15 || limit.Value < 1 || limit.Value > 100))
				{
					throw new ArgumentException("Invalid wave limit: " + creature.Key);
				}
			}
			List<string>[] array = new List<string>[2] { Minibosses, Bosses };
			foreach (List<string> list in array)
			{
				if (list.Count == 0 || list.Distinct().Count() != list.Count || list.Any((string name) => string.IsNullOrWhiteSpace(name) || !Creatures.TryGetValue(name, out CatalogCreature value2) || value2.Role == "excluded"))
				{
					throw new ArgumentException("Missing, excluded or duplicate creature in special wave roster.");
				}
			}
			foreach (KeyValuePair<string, CatalogCreature> creature2 in Creatures)
			{
				if (creature2.Value.Enabled && (creature2.Value.Role == "boss" || creature2.Value.Role == "miniboss") && !Minibosses.Contains(creature2.Key) && !Bosses.Contains(creature2.Key))
				{
					throw new ArgumentException("Enabled creature is absent from special wave rosters: " + creature2.Key);
				}
			}
			for (int num2 = 0; num2 < Layout.Count; num2++)
			{
				WavePlan wavePlan = Layout[num2];
				object obj;
				switch (num2)
				{
				default:
					obj = "regular";
					break;
				case 2:
				case 5:
				case 8:
					obj = "miniboss";
					break;
				case 9:
					obj = "boss";
					break;
				}
				string text = (string)obj;
				if (wavePlan == null || wavePlan.Kind != text || wavePlan.Standard < 0 || wavePlan.Magic < 0 || wavePlan.Rare < 0 || wavePlan.Standard > 100 || wavePlan.Magic > 100 || wavePlan.Rare > 100 || wavePlan.Standard + wavePlan.Magic + wavePlan.Rare == 0)
				{
					throw new ArgumentException("Invalid wave layout entry " + (num2 + 1));
				}
			}
		}

		public IReadOnlyList<string> Candidates(string role)
		{
			if (rosters.TryGetValue(role, out IReadOnlyList<string> value))
			{
				return value;
			}
			IEnumerable<string> source;
			if (!(role == "miniboss"))
			{
				if (!(role == "boss"))
				{
					source = from pair in Creatures
						where pair.Value.Role == role
						select pair.Key;
				}
				else
				{
					IEnumerable<string> bosses = Bosses;
					source = bosses;
				}
			}
			else
			{
				IEnumerable<string> bosses = Minibosses;
				source = bosses;
			}
			IReadOnlyList<string> readOnlyList = Array.AsReadOnly(source.Where((string name) => Creatures[name].Enabled).ToArray());
			rosters[role] = readOnlyList;
			return readOnlyList;
		}

		public bool Supports(int tier)
		{
			if (tier < 1 || tier > 15)
			{
				return false;
			}
			return new string[3] { "standard", "magic", "rare" }.Where((string role) => Layout.Any((WavePlan wave) => (!(role == "standard")) ? ((!(role == "magic")) ? (wave.Rare > 0) : (wave.Magic > 0)) : (wave.Standard > 0))).ToArray().Concat(new string[2] { "miniboss", "boss" })
				.All((string role) => Candidates(role).Count > 0);
		}

		internal CreatureEntry HazardEntry(string kind, int tier)
		{
			string text = kind switch
			{
				"tentacle" => "staff_greenroots_tentaroot", 
				"root" => "TentaRoot", 
				"brood_creature" => "SeekerBrood", 
				_ => throw new ArgumentException("Unknown hazard creature: " + kind), 
			};
			if (!Creatures.TryGetValue(text, out CatalogCreature value) || value.Stars == null)
			{
				throw new InvalidOperationException("Missing hazard star range: " + text);
			}
			CatalogStarRange catalogStarRange = value.RangeAt(tier);
			return new CreatureEntry
			{
				Prefab = text,
				Amount = 1,
				MinStars = catalogStarRange.MinStars,
				MaxStars = catalogStarRange.MaxStars
			};
		}

		public EventDefinition Build(int tier, EventDefinition settings)
		{
			if (!Supports(tier))
			{
				throw new ArgumentException("Monster catalog unavailable for tier.");
			}
			EventDefinition eventDefinition = new EventDefinition
			{
				Id = $"all-tier-{tier}",
				Tier = tier,
				Enabled = true,
				StartMessage = $"Tier {tier}. Ten waves.",
				EndMessage = $"Tier {tier} complete.",
				SpawnInterval = settings.SpawnInterval,
				GroupDelay = settings.GroupDelay,
				MaxAlive = settings.MaxAlive,
				Rewards = settings.Rewards
			};
			foreach (WavePlan item in Layout)
			{
				List<CreatureEntry> list = new List<CreatureEntry>();
				if (item.Kind != "regular")
				{
					Add(list, Candidates(item.Kind), tier, 1);
				}
				foreach (KeyValuePair<string, int> item2 in new Dictionary<string, int>
				{
					["standard"] = item.Standard,
					["magic"] = item.Magic,
					["rare"] = item.Rare
				})
				{
					if (item2.Value > 0)
					{
						Add(list, Candidates(item2.Key), tier, item2.Value);
					}
				}
				eventDefinition.Waves.Add(list);
			}
			eventDefinition.Validate();
			return eventDefinition;
		}

		private void Add(List<CreatureEntry> wave, IReadOnlyList<string> names, int tier, int amount)
		{
			string prefab = names[Random.Range(0, names.Count)];
			CatalogCreature catalogCreature = Creatures[prefab];
			CatalogStarRange catalogStarRange = catalogCreature.RangeAt(tier);
			if (catalogCreature.WaveLimits.TryGetValue(tier, out var value))
			{
				amount = Math.Min(amount, value - wave.Where((CreatureEntry entry) => entry.Prefab == prefab).Sum((CreatureEntry entry) => entry.Amount));
			}
			if (amount > 0)
			{
				wave.Add(new CreatureEntry
				{
					Prefab = prefab,
					Role = catalogCreature.Role,
					Amount = amount,
					MinStars = catalogStarRange.MinStars,
					MaxStars = catalogStarRange.MaxStars
				});
			}
		}
	}
	public sealed class CatalogCreature
	{
		public bool Enabled { get; set; }

		public string Role { get; set; } = "";

		public List<string> Biomes { get; set; } = new List<string>();

		public CatalogStarRange? Stars { get; set; }

		public Dictionary<int, int> WaveLimits { get; set; } = new Dictionary<int, int>();

		public string Notes { get; set; } = "";

		public CatalogStarRange RangeAt(int tier)
		{
			if (Stars == null || tier < 1 || tier > 15)
			{
				throw new ArgumentOutOfRangeException("tier", "A Tier 1 baseline and a tier from 1 to 15 are required.");
			}
			int num = 3 * (tier - 1);
			return new CatalogStarRange
			{
				MinStars = Stars.MinStars + num,
				MaxStars = Stars.MaxStars + num
			};
		}
	}
	public sealed class CatalogStarRange
	{
		public int MinStars { get; set; }

		public int MaxStars { get; set; }

		public string Status { get; set; } = "";
	}
	public sealed class WavePlan
	{
		public string Kind { get; set; } = "regular";

		public int Standard { get; set; }

		public int Magic { get; set; }

		public int Rare { get; set; }
	}
	public sealed class QuestReward
	{
		public string Prefab { get; set; } = "";

		public int Quantity { get; set; } = 1;

		public int Quality { get; set; } = 1;

		internal ItemData Item()
		{
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(Prefab);
			ItemDrop val = (((Object)(object)itemPrefab == (Object)null) ? null : itemPrefab.GetComponent<ItemDrop>());
			if ((Object)(object)val == (Object)null || Quality < 1 || Quality > val.m_itemData.m_shared.m_maxQuality || Quantity < 1 || Quantity > 10000)
			{
				throw new InvalidDataException($"Invalid reward {Prefab}: quantity={Quantity}, quality={Quality}.");
			}
			ItemData obj = val.m_itemData.Clone();
			obj.m_dropPrefab = itemPrefab;
			obj.m_quality = Quality;
			obj.m_stack = 1;
			obj.m_durability = obj.GetMaxDurability();
			return obj;
		}
	}
	public sealed class TierQuest
	{
		public int Tier { get; set; }

		public string Objective { get; set; } = "";

		public List<QuestReward> Rewards { get; set; } = new List<QuestReward>();

		[YamlIgnore]
		public string Error { get; internal set; } = "";

		internal void Validate()
		{
			if (Tier < 1 || Tier > 15 || string.IsNullOrWhiteSpace(Objective) || Objective.Length > 500 || Rewards == null || Rewards.Count < 1 || Rewards.Count > 32 || Rewards.Any((QuestReward r) => r == null || string.IsNullOrWhiteSpace(r.Prefab) || r.Prefab.Length > 128 || r.Quantity < 1 || r.Quantity > 10000 || r.Quality < 1 || r.Quality > 100))
			{
				throw new InvalidDataException($"Tier {Tier}: expected objective and 1–32 valid item rewards.");
			}
		}

		internal void ValidateItems()
		{
			Validate();
			int num = 0;
			foreach (QuestReward reward in Rewards)
			{
				ItemData val = reward.Item();
				num += (reward.Quantity + val.m_shared.m_maxStackSize - 1) / val.m_shared.m_maxStackSize;
			}
			if (num > 128)
			{
				throw new InvalidDataException($"Tier {Tier}: reward exceeds 128 stacks.");
			}
		}
	}
	public sealed class QuestCatalog
	{
		internal static readonly ISerializer Serializer = ((BuilderSkeleton<SerializerBuilder>)new SerializerBuilder()).WithNamingConvention(CamelCaseNamingConvention.Instance).Build();

		internal static readonly IDeserializer Deserializer = ((BuilderSkeleton<DeserializerBuilder>)new DeserializerBuilder()).WithNamingConvention(CamelCaseNamingConvention.Instance).WithDuplicateKeyChecking().Build();

		public int SchemaVersion { get; set; } = 1;

		public List<TierQuest> Tiers { get; set; } = new List<TierQuest>();

		internal TierQuest? Find(int tier)
		{
			return Tiers.FirstOrDefault((TierQuest t) => t.Tier == tier);
		}

		internal static QuestCatalog Load(string yaml)
		{
			QuestCatalog questCatalog = Deserializer.Deserialize<QuestCatalog>(yaml);
			if (questCatalog == null || questCatalog.SchemaVersion != 1 || questCatalog.Tiers == null || questCatalog.Tiers.Count > 15 || questCatalog.Tiers.Any((TierQuest t) => t == null || t.Tier < 1 || t.Tier > 15) || questCatalog.Tiers.Select((TierQuest t) => t.Tier).Distinct().Count() != questCatalog.Tiers.Count)
			{
				throw new InvalidDataException("quests.yaml: expected schemaVersion: 1 and unique tiers from 1 to 15.");
			}
			foreach (TierQuest tier in questCatalog.Tiers)
			{
				try
				{
					tier.Validate();
				}
				catch (Exception ex)
				{
					tier.Error = ex.Message;
				}
			}
			return questCatalog;
		}

		internal void ValidateItems(bool logErrors = true)
		{
			foreach (TierQuest tier in Tiers)
			{
				if (tier.Error.Length == 0)
				{
					try
					{
						tier.ValidateItems();
					}
					catch (Exception ex)
					{
						tier.Error = $"Tier {tier.Tier}: {ex.Message}";
					}
				}
				if (logErrors && tier.Error.Length != 0)
				{
					Debug.LogError((object)("[Valheim Endgame] Quest disabled: " + tier.Error));
				}
			}
		}

		internal static QuestCatalog Read(string directory)
		{
			string path = Path.Combine(directory, "quests.yaml");
			if (!File.Exists(path))
			{
				Directory.CreateDirectory(directory);
				QuestCatalog questCatalog = new QuestCatalog();
				for (int i = 1; i <= 15; i++)
				{
					questCatalog.Tiers.Add(new TierQuest
					{
						Tier = i,
						Objective = $"Complete a Tier {i} encounter. Stay alive inside the encounter when the final wave ends.",
						Rewards = new List<QuestReward>
						{
							new QuestReward
							{
								Prefab = TabletItem.PrefabName(Math.Min(i + 1, 15)),
								Quantity = ((i != 15) ? 1 : 5)
							}
						}
					});
				}
				using FileStream stream = new FileStream(path, FileMode.CreateNew, FileAccess.Write);
				using StreamWriter streamWriter = new StreamWriter(stream);
				streamWriter.WriteLine("# Restart the server/world after editing. Pending claims keep their original rewards.");
				streamWriter.Write(Serializer.Serialize((object)questCatalog));
			}
			return Load(File.ReadAllText(path));
		}
	}
	public sealed class RewardCatalog
	{
		public int SchemaVersion { get; set; } = 2;

		public List<RewardItem> Items { get; set; } = new List<RewardItem>();

		public List<RewardRarity> Rarities { get; set; } = new List<RewardRarity>();

		public RewardRules Rules { get; set; } = new RewardRules();

		public Dictionary<string, PopulationModifier> PopulationModifiers { get; set; } = new Dictionary<string, PopulationModifier>();

		public static RewardCatalog Load(string yaml)
		{
			RewardCatalog obj = Yaml.ConfigurationReader.Deserialize<RewardCatalog>(yaml) ?? throw new ArgumentException("rewards.yaml must contain a reward catalog.");
			obj.Validate();
			Require(obj.PopulationModifiers.Count == 4, "populationModifiers", "requires the four tablet population effects");
			return obj;
		}

		public void Validate()
		{
			Require(SchemaVersion == 2, "schemaVersion", "must be 2; replace the old base/wave roll settings with difficulty budgets");
			if (Items == null)
			{
				throw new ArgumentException("rewards.yaml items must contain item definitions.");
			}
			Require(Items.Count > 0 && Items.All((RewardItem i) => i != null), "items", "must contain item definitions");
			Require(Items.Select((RewardItem i) => i.Id).Distinct().Count() == Items.Count, "items", "IDs must be unique");
			foreach (RewardItem item in Items)
			{
				string text = "items." + item.Id;
				Require(!string.IsNullOrWhiteSpace(item.Id) && (item.RandomLegendarySetRune || !string.IsNullOrWhiteSpace(item.Prefab)), text, "requires id and prefab, or a random set reward");
				if (item.RandomLegendarySetRune)
				{
					Require(item.Prefab == "" && item.MinQuantity == 1 && item.MaxQuantity == 1 && item.TabletTier == 0 && item.TabletTheme == "", text, "random set rewards require quantity 1 and no prefab or tablet settings");
				}
				Require(item.MinTier >= 1 && item.MaxTier <= 15 && item.MinTier <= item.MaxTier, text, "tier range must be within 1–15");
				Require(item.MinQuantity >= 1 && item.MaxQuantity >= item.MinQuantity && item.MaxQuantity <= 1000, text, "quantity range must be within 1–1000");
				Require(item.TabletTier >= 0 && item.TabletTier <= 15, text + ".tabletTier", "must be 0 (encounter tier) or 1–15");
				Require(item.TabletTheme != null, text + ".tabletTheme", "must be a theme name or an empty string");
			}
			if (Rarities == null)
			{
				throw new ArgumentException("rewards.yaml rarities must contain ordered rarity tables.");
			}
			Require(Rarities.Count > 0 && Rarities.All((RewardRarity r) => r != null), "rarities", "must contain ordered rarity tables");
			Require(Rarities.Select((RewardRarity r) => r.Id).Distinct().Count() == Rarities.Count, "rarities", "IDs must be unique");
			foreach (RewardRarity rarity in Rarities)
			{
				string text2 = "rarities." + rarity.Id;
				Require(!string.IsNullOrWhiteSpace(rarity.Id) && Finite(rarity.Probability) && rarity.Probability >= 0.0 && rarity.Probability <= 1.0, text2, "requires an id and probability between 0 and 1");
				if (rarity.Entries == null)
				{
					throw new ArgumentException("rewards.yaml " + text2 + ".entries must be a list.");
				}
				Require(rarity.Entries.All((RewardWeight e) => e != null), text2 + ".entries", "must be a list");
				Require(rarity.Entries.Select((RewardWeight e) => e.Item).Distinct().Count() == rarity.Entries.Count, text2, "item references must be unique");
				foreach (RewardWeight entry in rarity.Entries)
				{
					Require(Items.Any((RewardItem i) => i.Id == entry.Item) && Finite(entry.Weight) && entry.Weight > 0.0 && entry.Weight <= 1000000.0, text2 + "." + entry.Item, "must reference an item with a positive weight no greater than 1000000");
				}
			}
			Require(Math.Abs(Rarities.Sum((RewardRarity r) => r.Probability) - 1.0) < 1E-06, "rarities", "overall probabilities must sum to 1");
			if (Rules == null)
			{
				throw new ArgumentException("rewards.yaml rules are required.");
			}
			Require(Finite(Rules.BudgetPerRoll) && Rules.BudgetPerRoll >= 0.01 && Rules.BudgetPerRoll <= 1000000.0 && Rules.MaxRolls >= 1 && Rules.MaxRolls <= 10000, "rules", "budgetPerRoll must be 0.01–1000000 and maxRolls must be 1–10000");
			Require(Rules.Tiers != null && Rules.Tiers.Count == 15 && Rules.Tiers.All((RewardTier t) => t != null && Finite(t.Difficulty) && t.Difficulty >= 0.0 && t.Difficulty <= 1000000.0 && Finite(t.BonusPercent) && t.BonusPercent >= 0.0 && t.BonusPercent <= 1000.0), "rules.tiers", "requires 15 finite difficulty and bonus rows");
			if (Rules.CategoryDifficulty == null || Rules.ModifierDifficulty == null)
			{
				throw new ArgumentException("rewards.yaml rules require categoryDifficulty and modifierDifficulty.");
			}
			string[] array = new string[4] { "population", "hazards", "totems", "creatures" };
			foreach (string text3 in array)
			{
				Require(Rules.CategoryDifficulty.TryGetValue(text3, out var value) && Finite(value) && value >= 0.0 && value <= 500.0, "rules.categoryDifficulty." + text3, "must be between 0 and 500 percent");
			}
			Require(Rules.ModifierDifficulty.All<KeyValuePair<string, double>>((KeyValuePair<string, double> p) => !string.IsNullOrWhiteSpace(p.Key) && Finite(p.Value) && p.Value >= 0.0 && p.Value <= 500.0), "rules.modifierDifficulty", "requires named contributions between 0 and 500 percent");
			Require(PopulationModifiers != null, "populationModifiers", "must be a mapping");
			if (PopulationModifiers.Count > 0)
			{
				string[] array2 = new string[4] { "VE_PopulationStandard", "VE_PopulationSupport", "VE_PopulationElite", "VE_PopulationBosses" };
				Require(PopulationModifiers.Count == array2.Length && array2.All((string id) => PopulationModifiers.TryGetValue(id, out PopulationModifier value2) && value2 != null), "populationModifiers", "requires all four population effects");
				array = array2;
				foreach (string text4 in array)
				{
					PopulationModifiers[text4].Validate(text4 == "VE_PopulationBosses");
				}
			}
			for (int num2 = 1; num2 <= 15; num2++)
			{
				for (int num3 = 0; num3 < Rarities.Count; num3++)
				{
					if (Rarities[num3].Probability > 0.0)
					{
						Require(Fallback(num3, num2) >= 0, "rarities." + Rarities[num3].Id, $"tier {num2} needs an eligible entry in this table or a lower rarity table");
					}
				}
			}
		}

		internal List<(RewardItem item, double weight)> Eligible(int rarity, int tier)
		{
			return (from e in Rarities[rarity].Entries
				select (item: Items.Single((RewardItem i) => i.Id == e.Item), weight: e.Weight) into e
				where e.item.Enabled && tier >= e.item.MinTier && tier <= e.item.MaxTier
				select e).ToList();
		}

		internal int Fallback(int rarity, int tier)
		{
			for (int i = rarity; i < Rarities.Count; i++)
			{
				if (Eligible(i, tier).Count > 0)
				{
					return i;
				}
			}
			return -1;
		}

		public Dictionary<string, double> EffectiveProbabilities(int tier)
		{
			Dictionary<string, double> dictionary = Rarities.ToDictionary((RewardRarity r) => r.Id, (RewardRarity _) => 0.0);
			for (int num = 0; num < Rarities.Count; num++)
			{
				if (Rarities[num].Probability > 0.0)
				{
					dictionary[Rarities[Fallback(num, tier)].Id] += Rarities[num].Probability;
				}
			}
			return dictionary;
		}

		internal RewardRollBudget Budget(int tier, double modifierDifficulty)
		{
			if (tier < 1 || tier > 15 || !Finite(modifierDifficulty) || modifierDifficulty < 0.0)
			{
				throw new ArgumentException("Reward rolls require tier 1–15 and finite nonnegative modifier difficulty.");
			}
			RewardTier rewardTier = Rules.Tiers[tier - 1];
			double num = rewardTier.Difficulty * (1.0 + modifierDifficulty / 100.0) * (1.0 + rewardTier.BonusPercent / 100.0);
			double num2 = Math.Round(num / Rules.BudgetPerRoll, 10, MidpointRounding.AwayFromZero);
			return new RewardRollBudget(rewardTier.Difficulty, rewardTier.BonusPercent, modifierDifficulty, num, Rules.BudgetPerRoll, Rules.MaxRolls, num2 > (double)Rules.MaxRolls, (int)Math.Min(Rules.MaxRolls, Math.Ceiling(num2)));
		}

		internal int Rolls(int tier, double modifierDifficulty)
		{
			return Budget(tier, modifierDifficulty).Rolls;
		}

		internal List<RewardOdds> Odds(int tier)
		{
			Dictionary<string, double> dictionary = EffectiveProbabilities(tier);
			List<RewardOdds> list = new List<RewardOdds>();
			for (int i = 0; i < Rarities.Count; i++)
			{
				double probability = dictionary[Rarities[i].Id];
				if (!(probability <= 0.0))
				{
					List<(RewardItem, double)> source = Eligible(i, tier);
					double total = source.Sum<(RewardItem, double)>(((RewardItem item, double weight) c) => c.weight);
					list.Add(new RewardOdds(Rarities[i].Id, probability, source.Select<(RewardItem, double), (RewardItem, double)>(((RewardItem item, double weight) c) => (item: c.item, probability * c.weight / total)).ToList()));
				}
			}
			return list;
		}

		internal double AtLeastOne(int tier, double modifierDifficulty, double probability)
		{
			return 1.0 - Math.Pow(1.0 - probability, Rolls(tier, modifierDifficulty));
		}

		private static bool Finite(double n)
		{
			if (!double.IsNaN(n))
			{
				return !double.IsInfinity(n);
			}
			return false;
		}

		private static void Require(bool valid, string path, string correction)
		{
			if (!valid)
			{
				throw new ArgumentException("rewards.yaml " + path + ": " + correction + ".");
			}
		}
	}
	internal sealed class RewardRollBudget
	{
		internal double TierDifficulty { get; }

		internal double TierBonusPercent { get; }

		internal double ModifierPercent { get; }

		internal double Budget { get; }

		internal double CostPerRoll { get; }

		internal int MaxRolls { get; }

		internal bool Capped { get; }

		internal int Rolls { get; }

		internal RewardRollBudget(double tierDifficulty, double tierBonusPercent, double modifierPercent, double budget, double costPerRoll, int maxRolls, bool capped, int rolls)
		{
			TierDifficulty = tierDifficulty;
			TierBonusPercent = tierBonusPercent;
			ModifierPercent = modifierPercent;
			Budget = budget;
			CostPerRoll = costPerRoll;
			MaxRolls = maxRolls;
			Capped = capped;
			Rolls = rolls;
		}
	}
	internal sealed class RewardOdds
	{
		internal string Rarity { get; }

		internal double Probability { get; }

		internal List<(RewardItem item, double probability)> Items { get; }

		internal RewardOdds(string rarity, double probability, List<(RewardItem item, double probability)> items)
		{
			Rarity = rarity;
			Probability = probability;
			Items = items;
		}
	}
	public sealed class RewardItem
	{
		public string Id { get; set; } = "";

		public string Prefab { get; set; } = "";

		public bool RandomLegendarySetRune { get; set; }

		public bool Enabled { get; set; } = true;

		public int MinTier { get; set; } = 1;

		public int MaxTier { get; set; } = 15;

		public int MinQuantity { get; set; } = 1;

		public int MaxQuantity { get; set; } = 1;

		public int TabletTier { get; set; }

		public string TabletTheme { get; set; } = "";
	}
	public sealed class RewardWeight
	{
		public string Item { get; set; } = "";

		public double Weight { get; set; } = 1.0;
	}
	public sealed class RewardRarity
	{
		public string Id { get; set; } = "";

		public double Probability { get; set; }

		public List<RewardWeight> Entries { get; set; } = new List<RewardWeight>();
	}
	public sealed class RewardRules
	{
		public double BudgetPerRoll { get; set; } = 10.0;

		public int MaxRolls { get; set; } = 10000;

		public List<RewardTier> Tiers { get; set; } = new List<RewardTier>();

		public Dictionary<string, double> CategoryDifficulty { get; set; } = new Dictionary<string, double>();

		public Dictionary<string, double> ModifierDifficulty { get; set; } = new Dictionary<string, double>();
	}
	public sealed class RewardTier
	{
		public double Difficulty { get; set; }

		public double BonusPercent { get; set; }
	}
	public sealed class RoomCatalog
	{
		public List<string> EnabledRooms { get; set; } = new List<string>();

		public Dictionary<string, string>? Themes { get; set; }

		public string DefaultBossRoom { get; set; } = "";

		public Dictionary<string, string?>? BossRooms { get; set; }

		public static RoomCatalog Load(string yaml)
		{
			RoomCatalog obj = Yaml.ConfigurationReader.Deserialize<RoomCatalog>(yaml) ?? throw new ArgumentException("Missing room configuration.");
			obj.Validate();
			return obj;
		}

		public void Validate()
		{
			if (EnabledRooms == null || EnabledRooms.Count == 0 || EnabledRooms.Any(string.IsNullOrWhiteSpace) || EnabledRooms.Distinct<string>(StringComparer.Ordinal).Count() != EnabledRooms.Count)
			{
				throw new ArgumentException("At least one unique room ID must be enabled in rooms.yaml.");
			}
			if (Themes == null || Themes.Any<KeyValuePair<string, string>>((KeyValuePair<string, string> pair) => string.IsNullOrWhiteSpace(pair.Key) || string.IsNullOrWhiteSpace(pair.Value)))
			{
				throw new ArgumentException("Every room theme assignment needs a room ID and a theme.");
			}
			foreach (string enabledRoom in EnabledRooms)
			{
				if (!Themes.ContainsKey(enabledRoom))
				{
					throw new ArgumentException("Assign a theme in rooms.yaml for room: " + enabledRoom);
				}
			}
			if (!Themes.ContainsKey(DefaultBossRoom))
			{
				throw new ArgumentException("defaultBossRoom in rooms.yaml must be a room with a theme.");
			}
			if (BossRooms == null)
			{
				throw new ArgumentException("Missing bossRooms in rooms.yaml.");
			}
			foreach (string item in EnabledRooms.Select((string id) => Themes[id]).Distinct<string>(StringComparer.Ordinal))
			{
				if (!BossRooms.ContainsKey(item))
				{
					throw new ArgumentException("Assign a boss room or null in rooms.yaml for theme: " + item);
				}
			}
			foreach (KeyValuePair<string, string> bossRoom in BossRooms)
			{
				if (bossRoom.Value != null && !Themes.ContainsKey(bossRoom.Value))
				{
					throw new ArgumentException("Boss room for theme " + bossRoom.Key + " is not a room with a theme: " + bossRoom.Value);
				}
			}
		}

		public string? ThemeFor(string id)
		{
			if (Themes == null || !Themes.TryGetValue(id, out string value))
			{
				return null;
			}
			return value;
		}

		public string BossRoomFor(string theme)
		{
			if (BossRooms == null || !BossRooms.TryGetValue(theme, out string value) || value == null)
			{
				return DefaultBossRoom;
			}
			return value;
		}
	}
	internal static class Yaml
	{
		internal static readonly ISerializer Writer = new SerializerBuilder().Build();

		internal static readonly ISerializer ConfigurationWriter = ((BuilderSkeleton<SerializerBuilder>)new SerializerBuilder()).WithNamingConvention(CamelCaseNamingConvention.Instance).Build();

		internal static readonly ISerializer JsonWriter = new SerializerBuilder().JsonCompatible().Build();

		internal static readonly IDeserializer Reader = new DeserializerBuilder().Build();

		internal static readonly IDeserializer CompatibleReader = new DeserializerBuilder().IgnoreUnmatchedProperties().Build();

		internal static readonly IDeserializer ConfigurationReader = ((BuilderSkeleton<DeserializerBuilder>)new DeserializerBuilder()).WithNamingConvention(CamelCaseNamingConvention.Instance).WithDuplicateKeyChecking().Build();
	}
	internal sealed class EncounterController : MonoBehaviour
	{
		internal const string PrefabName = "VE_EncounterController";

		internal const string AltarKey = "VE_SourceAltar";

		internal const string LinkKey = "VE_EncounterController";

		internal const string PendingKey = "VE_PendingController";

		internal const string ReturnKey = "VE_ReturnPosition";

		internal const string ReturnRotationKey = "VE_ReturnRotation";

		internal const string RecoveryKey = "VE_RecoveryPosition";

		internal const string MapKey = "VE_ExteriorPosition";

		internal const string SourceIdentityKey = "VE_AltarIdentity";

		internal const string ClosureReadyKey = "VE_ClosureReady";

		internal static void Register()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			if (!((Object)(object)PrefabManager.Instance.GetPrefab("VE_EncounterController") != (Object)null))
			{
				GameObject val = PrefabManager.Instance.CreateEmptyPrefab("VE_EncounterController", true);
				Object.DestroyImmediate((Object)(object)val.GetComponent<Collider>());
				Object.DestroyImmediate((Object)(object)val.GetComponent<MeshRenderer>());
				Object.DestroyImmediate((Object)(object)val.GetComponent<MeshFilter>());
				val.GetComponent<ZNetView>().m_persistent = true;
				val.AddComponent<EncounterController>();
				val.AddComponent<RoomRun>();
				PrefabManager.Instance.AddPrefab(new CustomPrefab(val, false));
			}
		}

		internal static bool IsController(ZDO record)
		{
			return record.GetPrefab() == StringExtensionMethods.GetStableHashCode("VE_EncounterController");
		}

		internal static void ReconnectSavedEncounters()
		{
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, ZDO[]> dictionary = (from record in ZDOMan.instance.m_objectsByID.Values
				where !IsController(record) && record.GetString("VE_AltarIdentity", "").Length != 0 && IsAltar(record)
				group record by record.GetString("VE_AltarIdentity", "")).ToDictionary((IGrouping<string, ZDO> group) => group.Key, (IGrouping<string, ZDO> group) => group.ToArray());
			foreach (ZDO item in dictionary.Values.SelectMany((ZDO[] records) => records))
			{
				item.Set("VE_EncounterController", ZDOID.None);
				item.Set("VE_PendingController", ZDOID.None);
			}
			List<ZDO> list = new List<ZDO>();
			EncounterObjects.Reset(ZDOMan.instance);
			foreach (ZDO value2 in ZDOMan.instance.m_objectsByID.Values)
			{
				EncounterObjects.Track(value2);
				if (IsController(value2))
				{
					list.Add(value2);
				}
			}
			EncounterPlacement.Reset(ZDOMan.instance, list);
			foreach (IGrouping<string, ZDO> item2 in from record in list
				group record by record.GetString("VE_AltarIdentity", ""))
			{
				ZDO[] array = item2.ToArray();
				ZDO[] array2 = array;
				for (int num = 0; num < array2.Length; num++)
				{
					array2[num].Set("VE_SourceAltar", ZDOID.None);
				}
				if (array.Length != 1 || !dictionary.TryGetValue(item2.Key, out var value) || value.Length != 1)
				{
					Debug.LogWarning((object)"[Valheim Endgame] Saved encounter retained: source altar is missing or ambiguous.");
					continue;
				}
				ZDO val = array[0];
				ZDO val2 = value[0];
				val.Set("VE_SourceAltar", val2.m_uid);
				if (val.GetBool("VE_Prepared", false))
				{
					EncounterTravel.FinishStart(val2, val);
				}
				else
				{
					val2.Set("VE_EncounterController", val.m_uid);
				}
			}
			foreach (ZDO altar in dictionary.Values.SelectMany((ZDO[] records) => records))
			{
				if (altar.GetBool("VE_ClosureReady", false) && !ZDOMan.instance.m_objectsByID.Values.Any((ZDO record) => IsController(record) && record.GetString("VE_AltarIdentity", "") == altar.GetString("VE_AltarIdentity", "")))
				{
					FinishClosure(altar);
				}
			}
		}

		internal static void FinishClosure(ZDO altar)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			altar.SetOwner(ZNet.GetUID());
			altar.Set("VE_EncounterController", ZDOID.None);
			altar.Set("VE_Room_State", 0);
			altar.Set("VE_Room_Player", 0L);
			altar.Set("VE_Room_CleanupStatus", "");
			altar.Set("VE_ClosureReady", false);
			ZDOMan.instance.ForceSendZDO(altar.m_uid);
		}

		internal static bool IsAltar(ZDO record)
		{
			GameObject prefab = ZNetScene.instance.GetPrefab(record.GetPrefab());
			int num = record.GetInt(ZDOVars.s_location, 0);
			if ((Object)(object)prefab != (Object)null && (Object)(object)prefab.GetComponent<LocationProxy>() != (Object)null)
			{
				return num == StringExtensionMethods.GetStableHashCode("MWL_MapRoom1");
			}
			return false;
		}

		internal static Transform Marker(Transform parent, string name, Vector3 position, Vector3 rotation = default(Vector3))
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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)
			Transform transform = new GameObject(name).transform;
			transform.SetParent(parent, false);
			transform.position = position;
			transform.rotation = Quaternion.Euler(rotation);
			return transform;
		}

		internal static void Bind(RoomRun run, ZDO record)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)run.ReturnPoint != (Object)null))
			{
				Vector3 vec = record.GetVec3("VE_ReturnPosition", Vector3.zero);
				if (vec == Vector3.zero)
				{
					throw new InvalidOperationException("Encounter return position is missing.");
				}
				run.ReturnPoint = Marker(((Component)run).transform, "Return", vec, record.GetVec3("VE_ReturnRotation", Vector3.zero));
				run.RecoveryPoint = Marker(((Component)run).transform, "Recovery", record.GetVec3("VE_RecoveryPosition", Vector3.zero));
			}
		}
	}
	internal static class EncounterIdentity
	{
		internal const string CreatureKey = "VE_EncounterCreature";

		private static readonly Dictionary<string, ZDOID> owners = new Dictionary<string, ZDOID>();

		private static ZDOMan? manager;

		internal static RoomRun? LoadedOwner(ZDO record)
		{
			string run = record.GetString("VE_Encounter", "");
			if (run.Length != 0)
			{
				return RoomRun.Loaded.FirstOrDefault((RoomRun room) => room.NetworkId != ZDOID.None && room.RunId == run);
			}
			return null;
		}

		internal static string AssignCreature(ZDO record)
		{
			string text = record.GetString("VE_EncounterCreature", "");
			if (text.Length != 0)
			{
				return text;
			}
			text = Guid.NewGuid().ToString("N");
			record.Set("VE_EncounterCreature", text);
			return text;
		}

		internal static ZDO? Owner(string run)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(run) || ZDOMan.instance == null)
			{
				return null;
			}
			if (manager != ZDOMan.instance)
			{
				owners.Clear();
				manager = ZDOMan.instance;
			}
			if (owners.TryGetValue(run, out var value))
			{
				ZDO zDO = manager.GetZDO(value);
				if (zDO != null && zDO.GetString("VE_Room_RunId", "") == run)
				{
					return zDO;
				}
				owners.Remove(run);
			}
			ZDO val = RoomRun.Loaded.FirstOrDefault((RoomRun room) => room.NetworkId != ZDOID.None && room.RunId == run)?.HazardData ?? ((IEnumerable<ZDO>)manager.m_objectsByID.Values).FirstOrDefault((Func<ZDO, bool>)((ZDO record) => record.GetString("VE_Room_RunId", "") == run));
			if (val != null)
			{
				owners[run] = val.m_uid;
			}
			return val;
		}
	}
	internal static class EncounterObjects
	{
		private const string Tag = "VE_Encounter";

		private static readonly int TagHash = StringExtensionMethods.GetStableHashCode("VE_Encounter");

		private static readonly Dictionary<string, HashSet<ZDOID>> runs = new Dictionary<string, HashSet<ZDOID>>(StringComparer.Ordinal);

		private static readonly Dictionary<ZDOID, (ZDO Record, string Run)> members = new Dictionary<ZDOID, (ZDO, string)>();

		private static ZDOMan? world;

		internal static bool Available => Ready;

		private static bool Ready
		{
			get
			{
				if (world != null && world == ZDOMan.instance && (Object)(object)ZNet.instance != (Object)null)
				{
					return ZNet.instance.IsServer();
				}
				return false;
			}
		}

		internal static void Clear()
		{
			world = null;
			runs.Clear();
			members.Clear();
		}

		internal static void Reset(ZDOMan manager)
		{
			Clear();
			world = manager;
		}

		internal static void Track(ZDO record)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			if (record.SaveClone || !Ready || world.GetZDO(record.m_uid) != record)
			{
				return;
			}
			string text = record.GetString("VE_Encounter", "");
			if (members.TryGetValue(record.m_uid, out (ZDO, string) value))
			{
				if (value.Item2 == text && value.Item1 == record)
				{
					return;
				}
				Remove(value.Item1);
			}
			if (text.Length != 0)
			{
				if (!runs.TryGetValue(text, out HashSet<ZDOID> value2))
				{
					value2 = new HashSet<ZDOID>();
					runs.Add(text, value2);
				}
				value2.Add(record.m_uid);
				members[record.m_uid] = (record, text);
			}
		}

		private static void Remove(ZDO record)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (members.TryGetValue(record.m_uid, out (ZDO, string) value) && value.Item1 == record)
			{
				members.Remove(record.m_uid);
				HashSet<ZDOID> hashSet = runs[value.Item2];
				hashSet.Remove(record.m_uid);
				if (hashSet.Count == 0)
				{
					runs.Remove(value.Item2);
				}
			}
		}

		internal static ZDO[] Records(string run)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			if (!Ready)
			{
				throw new InvalidOperationException("Saved encounter objects have not been indexed for this world.");
			}
			if (string.IsNullOrEmpty(run))
			{
				throw new InvalidOperationException("Encounter identity is missing.");
			}
			if (!runs.TryGetValue(run, out HashSet<ZDOID> value))
			{
				return Array.Empty<ZDO>();
			}
			List<ZDO> list = new List<ZDO>();
			ZDOID[] array = value.ToArray();
			foreach (ZDOID val in array)
			{
				ZDO zDO = world.GetZDO(val);
				(ZDO, string) value2;
				if (zDO != null && zDO.IsValid() && zDO.GetString("VE_Encounter", "") == run)
				{
					list.Add(zDO);
				}
				else if (members.TryGetValue(val, out value2))
				{
					Remove(value2.Item1);
					if (zDO != null && zDO.IsValid())
					{
						Track(zDO);
					}
				}
			}
			return list.ToArray();
		}

		[HarmonyPatch(typeof(ZDO), "Set", new Type[]
		{
			typeof(int),
			typeof(string)
		})]
		[HarmonyPostfix]
		private static void TagChanged(ZDO __instance, int hash)
		{
			if (hash == TagHash)
			{
				Track(__instance);
			}
		}

		[HarmonyPatch(typeof(ZDO), "Deserialize")]
		[HarmonyPostfix]
		private static void Received(ZDO __instance)
		{
			Track(__instance);
		}

		[HarmonyPatch(typeof(ZDO), "Reset")]
		[HarmonyPrefix]
		private static void Released(ZDO __instance)
		{
			if (!__instance.SaveClone)
			{
				Remove(__instance);
			}
		}
	}
	public sealed class EncounterMember
	{
		public long Id { get; set; }

		public string Name { get; set; } = "";

		public int Deaths { get; set; }

		public bool Active { get; set; }
	}
	internal sealed class EncounterParty
	{
		internal const string Key = "VE_Room_Participants";

		internal const string CompletionKey = "VE_Room_CompletionPlayers";

		internal const string EntryKey = "VE_EncounterActiveRun";

		internal const string LocalEntryKey = "warpalicious.ValheimEndgame.ActiveEncounter";

		internal const string DeathRunKey = "VE_EncounterDeathRun";

		internal const string DeathCountKey = "VE_EncounterDeaths";

		private string runId = "";

		private string source = "";

		private string completionSource = "";

		private Dictionary<long, EncounterMember> members = new Dictionary<long, EncounterMember>();

		private HashSet<long> eligible = new HashSet<long>();

		private bool dirty;

		internal IEnumerable<EncounterMember> Members => members.Values;

		internal int TotalDeaths { get; private set; }

		internal void Refresh(ZDO record, string run)
		{
			if (run != runId)
			{
				runId = run;
				source = "";
				completionSource = "";
				members.Clear();
				eligible.Clear();
				TotalDeaths = 0;
				dirty = false;
			}
			string text = record.GetString("VE_Room_Participants", "");
			if (text != source)
			{
				members = Deserialize(text).ToDictionary((EncounterMember member) => member.Id);
				TotalDeaths = members.Values.Sum((EncounterMember member) => member.Deaths);
				source = text;
				dirty = false;
			}
			string text2 = record.GetString("VE_Room_CompletionPlayers", "");
			if (text2 != completionSource)
			{
				eligible = new HashSet<long>(from member in Deserialize(text2)
					select member.Id);
				completionSource = text2;
			}
		}

		internal bool HasHistory(long id)
		{
			return members.ContainsKey(id);
		}

		internal bool IsActive(long id)
		{
			if (members.TryGetValue(id, out EncounterMember value))
			{
				return value.Active;
			}
			return false;
		}

		internal bool IsEligible(long id)
		{
			return eligible.Contains(id);
		}

		internal int Deaths(long id)
		{
			if (!members.TryGetValue(id, out EncounterMember value))
			{
				return 0;
			}
			return value.Deaths;
		}

		internal void Join(long id, string name)
		{
			if (!members.TryGetValue(id, out EncounterMember value))
			{
				if (members.Count >= 64)
				{
					throw new InvalidOperationException("Encounter participant limit reached.");
				}
				value = new EncounterMember
				{
					Id = id
				};
				members.Add(id, value);
				dirty = true;
			}
			if (value.Name != name)
			{
				value.Name = name;
				dirty = true;
			}
			SetActive(id, active: true);
		}

		internal void SetActive(long id, bool active)
		{
			if (members.TryGetValue(id, out EncounterMember value) && value.Active != active)
			{
				value.Active = active;
				dirty = true;
			}
		}

		internal void RecordDeaths(long id, int count)
		{
			if (members.TryGetValue(id, out EncounterMember value))
			{
				count = Math.Max(0, Math.Min(1000, count));
				if (count > value.Deaths)
				{
					TotalDeaths += count - value.Deaths;
					value.Deaths = count;
					dirty = true;
				}
			}
		}

		internal void Save(ZDO record)
		{
			if (dirty)
			{
				source = Yaml.Writer.Serialize((object)members.Values.ToList());
				record.Set("VE_Room_Participants", source);
				dirty = false;
			}
		}

		internal void CaptureCompletion(ZDO record, Func<long, bool> aliveInside)
		{
			List<EncounterMember> list = (from member in members.Values
				where member.Active && aliveInside(member.Id)
				select new EncounterMember
				{
					Id = member.Id,
					Name = member.Name
				}).ToList();
			completionSource = Yaml.Writer.Serialize((object)list);
			record.Set("VE_Room_CompletionPlayers", completionSource);
			eligible = new HashSet<long>(list.Select((EncounterMember member) => member.Id));
		}

		internal static List<EncounterMember> ReadCompletion(ZDO record)
		{
			return Deserialize(record.GetString("VE_Room_CompletionPlayers", ""));
		}

		private static List<EncounterMember> Deserialize(string value)
		{
			if (value.Length == 0)
			{
				return new List<EncounterMember>();
			}
			List<EncounterMember> list = Yaml.CompatibleReader.Deserialize<List<EncounterMember>>(value);
			if (list == null || list.Count > 64 || list.Any((EncounterMember member) => member == null || member.Id == 0L || member.Name == null || member.Deaths < 0 || member.Deaths > 1000) || list.Select((EncounterMember member) => member.Id).Distinct().Count() != list.Count)
			{
				throw new InvalidOperationException("Invalid encounter participants.");
			}
			return list;
		}
	}
	internal static class EncounterPlacement
	{
		internal const string RadiusKey = "VE_EncounterRadius";

		private static ZDOMan? world;

		private static readonly List<ZDO> occupied = new List<ZDO>();

		internal static void Remember(ZDO controller)
		{
			if (!occupied.Contains(controller))
			{
				occupied.Add(controller);
			}
		}

		internal static void Reset(ZDOMan manager, IEnumerable<ZDO> controllers)
		{
			world = manager;
			occupied.Clear();
			occupied.AddRange(controllers);
		}

		private static float WorldRadius()
		{
			Assembly assembly = Chainloader.PluginInfos.Values.Select((PluginInfo plugin) => ((object)plugin.Instance).GetType().Assembly).FirstOrDefault((Assembly assembly2) => assembly2.GetType("ExpandWorldSize.Configuration") != null);
			if (assembly == null)
			{
				return 10500f;
			}
			if (!(assembly.GetType("ExpandWorldSize.Configuration").GetProperty("WorldTotalRadius", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) is float num) || float.IsNaN(num) || float.IsInfinity(num) || num < 1f)
			{
				throw new InvalidOperationException("Cannot read Expand World Size's effective world boundary.");
			}
			return num;
		}

		internal static void ValidateExisting(ZDO controller)
		{
			//IL_0011: 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)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			float num = controller.GetFloat("VE_EncounterRadius", 0f);
			if (Utils.DistanceXZ(Vector3.zero, controller.GetPosition()) < WorldRadius() + num || !FitsSaveGrid(controller.GetPosition(), num))
			{
				throw new InvalidOperationException("The world boundary now overlaps this encounter. Recover it at the altar before starting another.");
			}
		}

		internal static Vector3 Allocate(out float reservedRadius)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			SimulationDistance val = SimulationDistance.GetSimulationDistance(GraphicsSettingIntExtentions.GetRange((GraphicsSettingInt)8192).m_maxValue);
			int totalSimulationDistance = ((SimulationDistance)(ref val)).TotalSimulationDistance;
			val = ZNet.instance.GetSyncedSimulationDistance();
			int num = Math.Max(totalSimulationDistance, ((SimulationDistance)(ref val)).TotalSimulationDistance);
			float maximumPlacementRadius = RoomAssets.MaximumPlacementRadius;
			if (maximumPlacementRadius <= 0f)
			{
				throw new InvalidOperationException("Room bounds are unavailable.");
			}
			reservedRadius = Mathf.Ceil((maximumPlacementRadius + (float)((num + 1) * 64) + 64f) / 64f) * 64f;
			float num2 = Mathf.Ceil((WorldRadius() + reservedRadius) / 64f) * 64f;
			if (world != ZDOMan.instance)
			{
				throw new InvalidOperationException("Saved encounter positions have not been read for this world.");
			}
			occupied.RemoveAll((ZDO record) => !record.IsValid() || world.GetZDO(record.m_uid) != record);
			int num3 = 0;
			int num4 = 0;
			while (num3 < 4096)
			{
				float num5 = num2 + (float)num4 * reservedRadius * 2f;
				int num6 = Mathf.Max(1, Mathf.FloorToInt((float)Math.PI / Mathf.Asin(reservedRadius / num5)));
				for (int num7 = 0; num7 < num6; num7++)
				{
					if (num3++ >= 4096)
					{
						break;
					}
					float num8 = (float)num7 * (float)Math.PI * 2f / (float)num6;
					Vector3 candidate = new Vector3(num5 * Mathf.Cos(num8), 5000f, num5 * Mathf.Sin(num8));
					if (FitsSaveGrid(candidate, reservedRadius))
					{
						float radius = reservedRadius;
						if (occupied.All((ZDO record) => Utils.DistanceXZ(candidate, record.GetPosition()) >= radius + record.GetFloat("VE_EncounterRadius", radius)))
						{
							return candidate;
						}
					}
				}
				num4++;
			}
			throw new InvalidOperationException("No separated encounter position fits the world's save grid.");
		}

		private static bool FitsSaveGrid(Vector3 position, float radius)
		{
			//IL_0007: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < 4; i++)
			{
				int num = Mathf.FloorToInt((position.x + (((i & 1) == 0) ? (0f - radius) : radius) + 32f) / 64f);
				int num2 = Mathf.FloorToInt((position.z + (((i & 2) == 0) ? (0f - radius) : radius) + 32f) / 64f);
				if (num < -32768 || num > 32767 || num2 < -32768 || num2 > 32767)
				{
					return false;
				}
				Vector2s val = ZoneSystem.IndexToSector(ZoneSystem.SectorToIndex(num, num2).Sector);
				if (val.x != num || val.y != num2)
				{
					return false;
				}
			}
			return true;
		}
	}
	internal static class EncounterPopulation
	{
		internal static int[] Counts(IReadOnlyList<CreatureEntry> wave, TabletEffects effects)
		{
			float value;
			int[] counts = wave.Select((CreatureEntry entry) => Mathf.CeilToInt((float)entry.Amount * (effects.PopulationByRole.TryGetValue(entry.Role, out value) ? value : 1f))).ToArray();
			int[] array = (from index in Enumerable.Range(0, wave.Count)
				where counts[index] > 0 && (wave[index].Role == "boss" || wave[index].Role == "miniboss")
				select index).ToArray();
			if (array.Length != 0)
			{
				for (int num = 0; num < effects.ExtraBossesPerWave; num++)
				{
					counts[array[num % array.Length]]++;
				}
			}
			return counts;
		}
	}
	public sealed class EncounterReward
	{
		public string Run { get; set; } = "";

		public int Tier { get; set; }

		public int Height { get; set; }

		public long CompletedAt { get; set; }

		public string Items { get; set; } = "";

		public bool Collected { get; set; }

		[YamlIgnore]
		public bool Valid
		{
			get
			{
				if (Guid.TryParseExact(Run, "N", out var _) && Tier >= 1 && Tier <= 15 && Height >= 8 && Height <= 1250 && CompletedAt > 0)
				{
					long completedAt = CompletedAt;
					DateTime maxValue = DateTime.MaxValue;
					if (completedAt <= maxValue.Ticks)
					{
						return !string.IsNullOrEmpty(Items);
					}
				}
				return false;
			}
		}

		internal static string Save(Inventory inventory)
		{
			//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();
			inventory.Save(val);
			return Convert.ToBase64String(val.GetArray());
		}

		internal Inventory Load()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Expected O, but got Unknown
			//IL_0052: Expected O, but got Unknown
			if (!Valid)
			{
				throw new InvalidOperationException("Invalid saved encounter reward.");
			}
			Inventory val = new Inventory($"Tier {Tier} encounter rewards", (Sprite)null, 8, Height);
			val.Load(new ZPackage(Convert.FromBase64String(Items)));
			Compact(val);
			return val;
		}

		internal static void Compact(Inventory inventory)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			List<ItemData> allItemsInGridOrder = inventory.GetAllItemsInGridOrder();
			for (int i = 0; i < allItemsInGridOrder.Count; i++)
			{
				allItemsInGridOrder[i].m_gridPos = new Vector2i(i % 8, i / 8);
			}
			inventory.SetHeight(Math.Max(1, (allItemsInGridOrder.Count + 7) / 8));
		}
	}
	internal sealed class QuestService : MonoBehaviour
	{
		private CustomRPC rpc;

		private QuestData data = new QuestData();

		private ZNet? network;

		private long world;

		private string path = "";

		private bool ready;

		private bool itemsChecked;

		private string failure = "";

		private Coroutine? requestTimeout;

		private Player? local;

		private readonly Dictionary<long, float> rateLimits = new Dictionary<long, float>();

		internal IEnumerable<EncounterReward> EncounterRewards => from reward in Progress.EncounterRewards.Where((EncounterReward reward) => !EncounterRewardCollection.Collected(world, reward.Run)).Concat(EncounterRewardCollection.Pending(world))
			group reward by reward.Run into @group
			select @group.First() into reward
			orderby reward.CompletedAt
			select reward;

		internal static QuestService? Instance { get; private set; }

		internal QuestCatalog Catalog { get; private set; } = new QuestCatalog();

		internal QuestPlayer Progress { get; private set; } = new QuestPlayer();

		internal string Status { get; private set; } = "Loading quests…";

		internal bool Pending => requestTimeout != null;

		internal long World => world;

		internal static event Action? Changed;

		private static QuestPlayer PlayerSnapshot(QuestPlayer player)
		{
			return new QuestPlayer
			{
				Id = player.Id,
				Account = player.Account,
				Completed = new HashSet<int>(player.Completed),
				Claims = player.Claims.ToList(),
				EncounterRewards = player.EncounterRewards.Select((EncounterReward reward) => new EncounterReward
				{
					Run = reward.Run,
					Tier = reward.Tier,
					Height = reward.Height,
					CompletedAt = reward.CompletedAt
				}).ToList()
			};
		}

		internal bool RecordEncounterRewards(ZDO record, string run, IEnumerable<EncounterMember> members)
		{
			if (!Ready() || !network.IsServer())
			{
				return false;
			}
			if (data.RewardedRuns.Contains(run))
			{
				return true;
			}
			EventDefinition definition = Yaml.CompatibleReader.Deserialize<EventDefinition>(record.GetString("VE_Room_Definition", ""));
			TabletEffects effects = Yaml.CompatibleReader.Deserialize<TabletEffects>(record.GetString("VE_Room_Effects", ""));
			Dictionary<long, EncounterReward> allocations = members.ToDictionary((EncounterMember m) => m.Id, delegate
			{
				Inventory val = RewardItems.Roll(definition.Rewards, definition.Tier, effects.LootBonusPercent);
				return new EncounterReward
				{
					Run = run,
					Tier = definition.Tier,
					Height = val.GetHeight(),
					CompletedAt = DateTime.UtcNow.Ticks,
					Items = EncounterReward.Save(val)
				};
			});
			return Commit(delegate(QuestData candidate)
			{
				foreach (KeyValuePair<long, EncounterReward> item in allocations)
				{
					candidate.Player(item.Key).EncounterRewards.Add(item.Value);
				}
				candidate.RewardedRuns.Add(run);
			});
		}

		internal void ClaimEncounter(string run)
		{
			if (!Pending)
			{
				if (EncounterRewardCollection.Has(world, run))
				{
					EncounterRewardCollection.Open(world, run);
				}
				else
				{
					Send("encounter", 0, run);
				}
			}
		}

		internal void ConfirmEncounter(string run)
		{
			if (Progress.EncounterRewards.Any((EncounterReward reward) => reward.Run == run))
			{
				Send("encounterAck", 0, run);
			}
		}

		private void HandleEncounter(QuestPlayer progress, string action, string run, QuestReply reply)
		{
			EncounterReward encounterReward = progress.EncounterRewards.FirstOrDefault((EncounterReward r) => r.Run == run);
			if (encounterReward == null)
			{
				reply.Message = "This encounter reward is unavailable or already claimed.";
			}
			else if (action == "encounter")
			{
				reply.EncounterDelivery = encounterReward;
			}
			else if (!Commit(delegate(QuestData candidate)
			{
				candidate.Player(progress.Id).EncounterRewards.RemoveAll((EncounterReward r) => r.Run == run);
			}))
			{
				reply.Message = "Could not confirm the reward receipt. Reopen Rewards to retry.";
			}
		}

		private void Awake()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_002e: Expected O, but got Unknown
			Instance = this;
			rpc = NetworkManager.Instance.AddRPC("TierQuests", new CoroutineHandler(ReceiveRequest), new CoroutineHandler(ReceiveReply));
			ItemManager.OnItemsRegistered += ValidateServerItems;
			PrefabManager.OnPrefabsRegistered += ValidateServerItems;
		}

		private bool Ready()
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null || instance.GetWorld() == null)
			{
				return false;
			}
			long worldUID = instance.GetWorldUID();
			if ((Object)(object)network == (Object)(object)instance && world == worldUID)
			{
				return ready;
			}
			ResetWorld();
			network = instance;
			world = worldUID;
			path = Path.Combine(Paths.BepInExRootPath, "data", "ValheimEndgame", "quests-" + world + ".yaml");
			try
			{
				if (instance.IsServer())
				{
					data = QuestData.Load(path);
					try
					{
						Catalog = QuestCatalog.Read(Path.Combine(Paths.ConfigPath, "ValheimEndgame"));
					}
					catch (Exception ex)
					{
						failure = "Quest configuration unavailable. Check the server log.";
						Debug.LogError((object)("[Valheim Endgame] " + ex));
					}
				}
				ready = true;
			}
			catch (Exception ex2)
			{
				Status = "Quest progress unavailable. Check the server log.";
				Debug.LogError((object)("[Valheim Endgame] " + ex2));
			}
			QuestService.Changed?.Invoke();
			return ready;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ZNet), "Awake")]
		private static void EnterWorld()
		{
			Instance?.Ready();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(ZNet), "OnDestroy")]
		private static void LeaveWorld()
		{
			Instance?.ResetWorld();
			QuestService.Changed?.Invoke();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Game), "SpawnPlayer")]
		private static void PlayerSpawned(Player __result)
		{
			Instance?.RequestForPlayer(__result);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "SetIntro")]
		private static void IntroChanged(Player __instance, bool intro)
		{
			if (!intro)
			{
				Instance?.RequestForPlayer(__instance);
			}
		}

		private void RequestForPlayer(Player player)
		{
			if (!((Object)(object)player == (Object)null) && !((Object)(object)player != (Object)(object)Player.m_localPlayer) && !((Character)player).InIntro() && Ready() && !((Object)(object)player == (Object)(object)local))
			{
				local = player;
				Request();
			}
		}

		private void ValidateServerItems()
		{
			if (Ready() && network.IsServer() && !itemsChecked && (Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ObjectDB.instance != (Object)null)
			{
				Catalog.ValidateItems();
				itemsChecked = true;
			}
		}

		private void ResetWorld()
		{
			CancelRequestTimeout();
			network = null;
			world = 0L;
			path = "";
			ready = false;
			itemsChecked = false;
			local = null;
			data = new QuestData();
			Catalog = new QuestCatalog();
			Progress = new QuestPlayer();
			rateLimits.Clear();
			failure = "";
			Status = "Loading quests…";
		}

		private void CancelRequestTimeout()
		{
			if (requestTimeout != null)
			{
				((MonoBehaviour)this).StopCoroutine(requestTimeout);
			}
			requestTimeout = null;
		}

		private IEnumerator RequestTimedOut()
		{
			yield return (object)new WaitForSecondsRealtime(10f);
			requestTimeout = null;
			Status = "Request timed out. Reopen the shop or try again.";
			QuestService.Changed?.Invoke();
		}

		internal bool RecordCompletion(IEnumerable<EncounterMember> members, int tier)
		{
			if (!Ready() || !network.IsServer() || tier < 1 || tier > 15)
			{
				return false;
			}
			long[] ids = members.Select((EncounterMember m) => m.Id).Distinct().ToArray();
			if (ids.All((long id) => data.Players.Any((QuestPlayer p) => p.Id == id && p.Completed.Contains(tier))))
			{
				return true;
			}
			return Commit(delegate(QuestData candidate)
			{
				long[] array = ids;
				foreach (long id in array)
				{
					candidate.Player(id).Completed.Add(tier);
				}
			});
		}

		private bool Commit(Action<QuestData> update)
		{
			try
			{
				QuestData questData = data.Copy();
				update(questData);
				questData.Save(path);
				data = questData;
				return true;
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[Valheim Endgame] Quest ledger write failed: " + ex));
				return false;
			}
		}

		internal void Request()
		{
			Send("status", 0, "");
		}

		internal void Claim(int tier)
		{
			if (!Pending)
			{
				Send("claim", tier, "");
			}
		}

		internal void SetProgress(int tier)
		{
			Send("setProgress", tier, "");
		}

		private void Send(string action, int tier, string transaction)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			if (Ready() && !((Object)(object)Player.m_localPlayer == (Object)null) && ZRoutedRpc.instance != null)
			{
				CancelRequestTimeout();
				requestTimeout = ((MonoBehaviour)this).StartCoroutine(RequestTimedOut());
				Status = "";
				QuestService.Changed?.Invoke();
				if (network.IsServer())
				{
					QuestReply reply = Handle(Player.m_localPlayer.GetPlayerID(), "local", admin: true, action, tier, transaction);
					Apply(reply);
					return;
				}
				ZPackage val = new ZPackage();
				val.Write(action);
				val.Write(tier);
				val.Write(transaction);
				rpc.SendPackage(ZRoutedRpc.instance.GetServerPeerID(), val);
			}
		}

		private QuestReply Handle(long id, string account, bool admin, string action, int tier, string transaction)
		{
			ValidateServerItems();
			QuestReply questReply = new QuestReply
			{
				World = world,
				Catalog = QuestCatalog.Serializer.Serialize((object)Catalog)
			};
			QuestPlayer questPlayer = data.Players.FirstOrDefault((QuestPlayer p) => p.Id == id);
			if (questPlayer != null && questPlayer.Account.Length > 0 && questPlayer.Account != account)
			{
				questReply.Message = "Character identity belongs to a different account.";
				return questReply;
			}
			if ((questPlayer == null || questPlayer.Account.Length == 0) && !Commit(delegate(QuestData candidate)
			{
				candidate.Player(id).Account = account;
			}))
			{
				questReply.Message = "Could not save quest progress. Try again.";
				return questReply;
			}
			QuestPlayer questPlayer2 = data.Player(id);
			if ((action == "encounter" || action == "encounterAck") ? true : false)
			{
				HandleEncounter(questPlayer2, action, transaction, questReply);
				questReply.Player = PlayerSnapshot(data.Player(id));
				return questReply;
			}
			QuestClaim questClaim = questPlayer2.Claims.FirstOrDefault((QuestClaim c) => c.Tier == tier);
			switch (action)
			{
			case "claim":
			{
				TierQuest quest = Catalog.Find(tier);
				if (!questPlayer2.Completed.Contains(tier))
				{
					questReply.Message = "Complete this tier before claiming its reward.";
				}
				else if (questClaim != null && questClaim.Delivered)
				{
					questReply.Message = "Reward already claimed.";
				}
				else if (questClaim != null)
				{
					questReply.Delivery = questClaim;
				}
				else if (!itemsChecked || quest == null || quest.Error.Length != 0 || failure.Length != 0)
				{
					questReply.Message = "This tier's reward is unavailable. Check the server configuration.";
				}
				else if (Commit(delegate(QuestData candidate)
				{
					candidate.Player(id).Claims.Add(new QuestClaim
					{
						Tier = tier,
						Transaction = Guid.NewGuid().ToString("N"),
						Rewards = quest.Rewards
					});
				}))
				{
					questReply.Delivery = data.Player(id).Claims.Single((QuestClaim c) => c.Tier == tier);
				}
				else
				{
					questReply.Message = "Could not save the claim. Try again.";
				}
				break;
			}
			case "setProgress":
				if (!admin)
				{
					questReply.Message = "Only an admin can set Endgame progress.";
				}
				else if (tier < 0 || tier > 15)
				{
					questReply.Message = "Progress tier must be 0–15.";
				}
				else if (Commit(delegate(QuestData candidate)
				{
					QuestPlayer questPlayer3 = candidate.Player(id);
					questPlayer3.Completed = new HashSet<int>(Enumerable.Range(1, tier));
					questPlayer3.Claims.RemoveAll((QuestClaim c) => c.Tier > tier);
				}))
				{
					questReply.Message = $"Progress tier set to {tier}.";
				}
				else
				{
					questReply.Message = "Could not save progress. Try again.";
				}
				break;
			case "ack":
				if (questClaim == null || questClaim.Transaction != transaction)
				{
					questReply.Message = "Unknown reward receipt.";
				}
				else if (!questClaim.Delivered && !Commit(delegate(QuestData candidate)
				{
					candidate.Player(id).Claims.Single((QuestClaim c) => c.Tier == tier).Delivered = true;
				}))
				{
					questReply.Message = "Receipt saved on your character. Retry to confirm it with the server.";
				}
				break;
			case "status":
				questReply.Delivery = questPlayer2.Claims.FirstOrDefault((QuestClaim c) => !c.Delivered);
				break;
			default:
				questReply.Message = "Unknown quest request.";
				break;
			}
			questReply.Player = PlayerSnapshot(data.Player(id));
			if (questReply.Message.Length == 0 && failure.Length != 0)
			{
				questReply.Message = failure;
			}
			return questReply;
		}

		private IEnumerator ReceiveRequest(long sender, ZPackage package)
		{
			if (!Ready() || !network.IsServer())
			{
				yield break;
			}
			ZNetPeer val = ((IEnumerable<ZNetPeer>)network.GetPeers()).FirstOrDefault((Func<ZNetPeer, bool>)((ZNetPeer p) => p.IsReady() && p.m_uid == sender));
			if (val == null)
			{
				yield break;
			}
			ZDO zDO = ZDOMan.instance.GetZDO(val.m_characterID);
			long num = ((zDO != null) ? zDO.GetLong(ZDOVars.s_playerID, 0L) : 0);
			if (num == 0L)
			{
				yield break;
			}
			try
			{
				string text = package.ReadString();
				int tier = package.ReadInt();
				string text2 = package.ReadString();
				bool flag = ((text == "ack" || text == "encounterAck") ? true : false);
				if (flag || !rateLimits.TryGetValue(sender, out var value) || !(Time.unscaledTime - value < 0.2f))
				{
					rateLimits[sender] = Time.unscaledTime;
					if (text2.Length <= 32)
					{
						string hostName = val.m_socket.GetHostName();
						QuestReply questReply = Handle(num, hostName, network.IsAdmin(hostName), text, tier, text2);
						ZPackage val2 = new ZPackage();
						val2.Write(QuestCatalog.Serializer.Serialize((object)questReply));
						rpc.SendPackage(sender, val2);
					}
				}
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("[Valheim Endgame] Quest request rejected: " + ex.Message));
			}
		}

		private IEnumerator ReceiveReply(long sender, ZPackage package)
		{
			if (!Ready() || network.IsServer() || ZRoutedRpc.instance == null || sender != ZRoutedRpc.instance.GetServerPeerID())
			{
				yield break;
			}
			try
			{
				Apply(QuestCatalog.Deserializer.Deserialize<QuestReply>(package.ReadString()));
			}
			catch (Exception ex)
			{
				CancelRequestTimeout();
				Status = "Invalid quest response.";
				QuestService.Changed?.Invoke();
				Debug.LogWarning((object)("[Valheim Endgame] " + ex));
			}
		}

		private void Apply(QuestReply reply)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || reply.World != world)
			{
				return;
			}
			CancelRequestTimeout();
			Status = reply.Message;
			if (reply.Player.Id != localPlayer.GetPlayerID())
			{
				QuestService.Changed?.Invoke();
				return;
			}
			int num = ((Progress.Id == localPlayer.GetPlayerID()) ? Progress.ProgressTier() : (-1));
			Catalog = QuestCatalog.Load(reply.Catalog);
			Catalog.ValidateItems(logErrors: false);
			Progress = reply.Player;
			QuestService.Changed?.Invoke();
			if (num >= 0 && Progress.ProgressTier() > num && Status.Length == 0)
			{
				((Character)localPlayer).Message((MessageType)2, $"Progress tier {Progress.ProgressTier()}. Dungeon Master tablets: {TabletProgression.Describe(Progress.ProgressTier())}.", 0, (Sprite)null, false);
			}
			if (reply.EncounterDelivery != null)
			{
				try
				{
					EncounterRewardCollection.Receive(localPlayer, world, reply.EncounterDelivery);
					EncounterRewardCollection.Open(world, reply.EncounterDelivery.Run);
				}
				catch (Exception ex)
				{
					Status = ex.Message;
					QuestService.Changed?.Invoke();
					((Character)localPlayer).Message((MessageType)2, Status, 0, (Sprite)null, false);
				}
			}
			if (reply.Delivery != null)
			{
				try
				{
					QuestDelivery.Deliver(localPlayer, world, reply.Delivery);
					Send("ack", reply.Delivery.Tier, reply.Delivery.Transaction);
					return;
				}
				catch (Exception ex2)
				{
					Status = ex2.Message;
					QuestService.Changed?.Invoke();
					((Character)localPlayer).Message((MessageType)2, Status, 0, (Sprite)null, false);
					return;
				}
			}
			if (Status.Length > 0)
			{
				((Character)localPlayer).Message((MessageType)2, Status, 0, (Sprite)null, false);
			}
		}

		private void OnDestroy()
		{
			ItemManager.OnItemsRegistered -= ValidateServerItems;
			PrefabManager.OnPrefabsRegistered -= ValidateServerItems;
			CancelRequestTimeout();
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}
	}
	internal sealed class EncounterRewardCollection : MonoBehaviour
	{
		private const string KeyPrefix = "warpalicious.ValheimEndgame.EncounterRewards.";

		private static EncounterRewardCollection? active;

		private static InventoryGrid? compactedGrid;

		private Inventory inventory;

		private EncounterReward reward;

		private Player player;

		private long world;

		private Container container;

		private static List<string> savedFinished = new List<string>();

		private static List<EncounterReward> Read(Player player, long world)
		{
			if (!player.m_customData.TryGetValue("warpalicious.ValheimEndgame.EncounterRewards." + world, out var value))
			{
				return new List<EncounterReward>();
			}
			return QuestCatalog.Deserializer.Deserialize<List<EncounterReward>>(value);
		}

		private static void Write(Player player, long world, List<EncounterReward> rewards)
		{
			player.m_customData["warpalicious.ValheimEndgame.EncounterRewards." + world] = QuestCatalog.Serializer.Serialize((object)rewards);
		}

		internal static bool Has(long world, string run)
		{
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				return Read(Player.m_localPlayer, world).Any((EncounterReward reward) => reward.Run == run);
			}
			return false;
		}

		internal static bool Collected(long world, string run)
		{
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				return Read(Player.m_localPlayer, world).Any((EncounterReward reward) => reward.Run == run && reward.Collected);
			}
			return false;
		}

		internal static IEnumerable<EncounterReward> Pending(long world)
		{
			if (!((Object)(object)Player.m_localPlayer == (Object)null))
			{
				return from reward in Read(Player.m_localPlayer, world)
					where !reward.Collected
					select reward;
			}
			return Enumerable.Empty<EncounterReward>();
		}

		internal static void Receive(Player player, long world, EncounterReward reward)
		{
			List<EncounterReward> list = Read(player, world);
			if (list.All((EncounterReward existing) => existing.Run != reward.Run))
			{
				reward.Collected = reward.Load().NrOfItems() == 0;
				list.Add(reward);
				Write(player, world, list);
			}
		}

		internal static void Open(long world, string run)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			if ((Object)(object)active != (Object)null)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			EncounterReward encounterReward = Read(localPlayer, world).FirstOrDefault((EncounterReward r) => r.Run == run);
			if (encounterReward == null)
			{
				return;
			}
			Inventory val = encounterReward.Load();
			if (val.NrOfItems() != 0)
			{
				StoreGui instance = StoreGui.instance;
				if (instance != null)
				{
					instance.Hide();
				}
				GameObject val2 = new GameObject("Personal encounter rewards");
				val2.transform.SetParent(((Component)localPlayer).transform, false);
				EncounterRewardCollection encounterRewardCollection = val2.AddComponent<EncounterRewardCollection>();
				encounterRewardCollection.player = localPlayer;
				encounterRewardCollection.world = world;
				encounterRewardCollection.reward = encounterReward;
				encounterRewardCollection.inventory = val;
				encounterRewardCollection.container = val2.AddComponent<Container>();
				active = encounterRewardCollection;
				val.m_onChanged = (Action)Delegate.Combine(val.m_onChanged, new Action(encounterRewardCollection.InventoryChanged));
				InventoryGui.instance.Show(encounterRewardCollection.container, 1);
			}
		}

		private void InventoryChanged()
		{
			EncounterReward.Compact(inventory);
			UpdateReceipt();
		}

		private void UpdateReceipt()
		{
			reward.Items = EncounterReward.Save(inventory);
			reward.Collected = inventory.NrOfItems() == 0;
			List<EncounterReward> list = Read(player, world);
			int num = list.FindIndex((EncounterReward existing) => existing.Run == reward.Run);
			if (num < 0)
			{
				throw new InvalidOperationException("The reward receipt is missing.");
			}
			list[num] = reward;
			Write(player, world, list);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerProfile), "SavePlayerData")]
		private static void CharacterSerialized(Player player)
		{
			QuestService instance = QuestService.Instance;
			savedFinished = (((Object)(object)player == (Object)(object)Player.m_localPlayer && (Object)(object)instance != (Object)null) ? (from reward in Read(player, instance.World)
				where reward.Collected
				select reward.Run).ToList() : new List<string>());
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerProfile), "Save")]
		private static void CharacterSaved(bool __result)
		{
			if (__result)
			{
				foreach (string item in savedFinished)
				{
					QuestService.Instance?.ConfirmEncounter(item);
				}
			}
			savedFinished.Clear();
		}

		private void OnDestroy()
		{
			if (inventory != null)
			{
				Inventory obj = inventory;
				obj.m_onChanged = (Action)Delegate.Remove(obj.m_onChanged, new Action(InventoryChanged));
			}
			if ((Object)(object)active == (Object)(object)this)
			{
				RestoreGrid();
				active = null;
			}
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Container), "Awake")]
		private static bool InitializeContainer(Container __instance)
		{
			EncounterRewardCollection component = ((Component)__instance).GetComponent<EncounterRewardCollection>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			__instance.m_inventory = component.inventory;
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Container), "IsOwner")]
		private static bool IsOwner(Container __instance, ref bool __result)
		{
			if ((Object)(object)((Component)__instance).GetComponent<EncounterRewardCollection>() == (Object)null)
			{
				return true;
			}
			__result = true;
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Container), "SetInUse")]
		private static bool LocalContainer(Container __instance)
		{
			return (Object)(object)((Component)__instance).GetComponent<EncounterRewardCollection>() == (Object)null;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Container), "StackAll")]
		private static bool NoStackContainer(Container __instance)
		{
			return LocalContainer(__instance);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Container), "TakeAll")]
		private static bool TakeAll(Container __instance, Humanoid character, ref bool __result)
		{
			if ((Object)(object)((Component)__instance).GetComponent<EncounterRewardCollection>() == (Object)null)
			{
				return true;
			}
			character.GetInventory().MoveAll(__instance.GetInventory());
			__result = true;
			return false;
		}

		private static bool Collecting(InventoryGui gui)
		{
			if ((Object)(object)active != (Object)null)
			{
				return (Object)(object)gui.m_currentContainer == (Object)(object)active.container;
			}
			return false;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(InventoryGui), "UpdateContainer")]
		private static void RestoreOtherContainerSlots(InventoryGui __instance)
		{
			if (!Collecting(__instance))
			{
				RestoreGrid();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(InventoryGui), "UpdateContainer")]
		private static void UpdateRewardSlots(InventoryGui __instance)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			if (Collecting(__instance))
			{
				InventoryGrid containerGrid = __instance.m_containerGrid;
				if ((Object)(object)compactedGrid != (Object)(object)containerGrid)
				{
					RestoreGrid();
				}
				compactedGrid = containerGrid;
				int num = active.inventory.NrOfItems();
				int widt